diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2015-04-01 17:19:16 +0900 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2015-04-07 09:18:08 +0200 |
commit | 6d59210340cba4db7387e05eff302b59bd93dac3 (patch) | |
tree | d61f672f832486c41bb1c891ccb9f24af79cca3d /android/experimental | |
parent | bf995db73982016f6baf752e5cf03bca3975c640 (diff) |
android: replace TextSelection{Handle} with SelectionHandles
TextSelection was an additional overlay on the screen to show text
selection (start, middle, end) handles. Now they are replaced with
CanvasElement - SelectionHandle, that is drawn in TextCursorView
the same as cursor and text/graphic selections.
Change-Id: I30e1b00b349500c307d9b580abc4d30e3faf722d
Diffstat (limited to 'android/experimental')
13 files changed, 296 insertions, 381 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/InvalidationHandler.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/InvalidationHandler.java index 359f0ca71cd2..a49b32dad974 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/InvalidationHandler.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/InvalidationHandler.java @@ -4,10 +4,9 @@ import android.content.Intent; import android.graphics.RectF; import android.net.Uri; +import org.libreoffice.canvas.SelectionHandle; import org.libreoffice.kit.Document; import org.libreoffice.overlay.TextCursorLayer; -import org.mozilla.gecko.TextSelection; -import org.mozilla.gecko.TextSelectionHandle; import java.util.ArrayList; import java.util.Collections; @@ -19,12 +18,10 @@ import java.util.List; public class InvalidationHandler implements Document.MessageCallback { private static String LOGTAG = InvalidationHandler.class.getSimpleName(); private final TextCursorLayer mTextCursorLayer; - private final TextSelection mTextSelection; private OverlayState mState; public InvalidationHandler(LibreOfficeMainActivity mainActivity) { mTextCursorLayer = mainActivity.getTextCursorLayer(); - mTextSelection = mainActivity.getTextSelection(); mState = OverlayState.NONE; } @@ -150,8 +147,8 @@ public class InvalidationHandler implements Document.MessageCallback { private synchronized void invalidateCursor(String payload) { RectF cursorRectangle = convertPayloadToRectangle(payload); if (cursorRectangle != null) { - mTextSelection.positionHandle(TextSelectionHandle.HandleType.MIDDLE, cursorRectangle); mTextCursorLayer.positionCursor(cursorRectangle); + mTextCursorLayer.positionHandle(SelectionHandle.HandleType.MIDDLE, cursorRectangle); if (mState == OverlayState.TRANSITION || mState == OverlayState.CURSOR) { changeStateTo(OverlayState.CURSOR); @@ -167,7 +164,7 @@ public class InvalidationHandler implements Document.MessageCallback { private synchronized void textSelectionStart(String payload) { RectF selectionRect = convertPayloadToRectangle(payload); if (selectionRect != null) { - mTextSelection.positionHandle(TextSelectionHandle.HandleType.START, selectionRect); + mTextCursorLayer.positionHandle(SelectionHandle.HandleType.START, selectionRect); } } @@ -179,7 +176,7 @@ public class InvalidationHandler implements Document.MessageCallback { private synchronized void textSelectionEnd(String payload) { RectF selectionRect = convertPayloadToRectangle(payload); if (selectionRect != null) { - mTextSelection.positionHandle(TextSelectionHandle.HandleType.END, selectionRect); + mTextCursorLayer.positionHandle(SelectionHandle.HandleType.END, selectionRect); } } @@ -213,11 +210,11 @@ public class InvalidationHandler implements Document.MessageCallback { if (payload.equals("true")) { mTextCursorLayer.showCursor(); if (mState != OverlayState.SELECTION) { - mTextSelection.showHandle(TextSelectionHandle.HandleType.MIDDLE); + mTextCursorLayer.showHandle(SelectionHandle.HandleType.MIDDLE); } } else if (payload.equals("false")) { mTextCursorLayer.hideCursor(); - mTextSelection.hideHandle(TextSelectionHandle.HandleType.MIDDLE); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.MIDDLE); } } @@ -296,9 +293,9 @@ public class InvalidationHandler implements Document.MessageCallback { } // Just hide everything - mTextSelection.hideHandle(TextSelectionHandle.HandleType.START); - mTextSelection.hideHandle(TextSelectionHandle.HandleType.END); - mTextSelection.hideHandle(TextSelectionHandle.HandleType.MIDDLE); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.START); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.END); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.MIDDLE); mTextCursorLayer.hideSelections(); mTextCursorLayer.hideCursor(); mTextCursorLayer.hideGraphicSelection(); @@ -309,8 +306,8 @@ public class InvalidationHandler implements Document.MessageCallback { * Handle a transition to OverlayState.SELECTION state. */ private void handleSelectionState(OverlayState previous) { - mTextSelection.showHandle(TextSelectionHandle.HandleType.START); - mTextSelection.showHandle(TextSelectionHandle.HandleType.END); + mTextCursorLayer.showHandle(SelectionHandle.HandleType.START); + mTextCursorLayer.showHandle(SelectionHandle.HandleType.END); mTextCursorLayer.showSelections(); } @@ -320,7 +317,7 @@ public class InvalidationHandler implements Document.MessageCallback { private void handleCursorState(OverlayState previous) { LibreOfficeMainActivity.mAppContext.showSoftKeyboard(); if (previous == OverlayState.TRANSITION) { - mTextSelection.showHandle(TextSelectionHandle.HandleType.MIDDLE); + mTextCursorLayer.showHandle(SelectionHandle.HandleType.MIDDLE); mTextCursorLayer.showCursor(); } } @@ -330,11 +327,11 @@ public class InvalidationHandler implements Document.MessageCallback { */ private void handleTransitionState(OverlayState previous) { if (previous == OverlayState.SELECTION) { - mTextSelection.hideHandle(TextSelectionHandle.HandleType.START); - mTextSelection.hideHandle(TextSelectionHandle.HandleType.END); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.START); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.END); mTextCursorLayer.hideSelections(); } else if (previous == OverlayState.CURSOR) { - mTextSelection.hideHandle(TextSelectionHandle.HandleType.MIDDLE); + mTextCursorLayer.hideHandle(SelectionHandle.HandleType.MIDDLE); } else if (previous == OverlayState.GRAPHIC_SELECTION) { mTextCursorLayer.hideGraphicSelection(); } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java index 12f2731e5389..7067714fd1f6 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java @@ -11,12 +11,9 @@ package org.libreoffice; import android.graphics.PointF; import android.graphics.RectF; import android.view.KeyEvent; -import android.view.MotionEvent; -import org.mozilla.gecko.TextSelectionHandle; +import org.libreoffice.canvas.SelectionHandle; import org.mozilla.gecko.gfx.ComposedTileLayer; -import org.mozilla.gecko.gfx.IntSize; -import org.mozilla.gecko.gfx.SubTile; /** * Events and data that is queued and processed by LOKitThread. @@ -49,7 +46,7 @@ public class LOEvent implements Comparable<LOEvent> { public PointF mDocumentCoordinate; public KeyEvent mKeyEvent; public RectF mInvalidationRect; - public TextSelectionHandle.HandleType mHandleType; + public SelectionHandle.HandleType mHandleType; public LOEvent(int type) { mType = type; @@ -98,7 +95,7 @@ public class LOEvent implements Comparable<LOEvent> { mInvalidationRect = rect; } - public LOEvent(int type, TextSelectionHandle.HandleType handleType, PointF documentCoordinate) { + public LOEvent(int type, SelectionHandle.HandleType handleType, PointF documentCoordinate) { mType = type; mHandleType = handleType; mDocumentCoordinate = documentCoordinate; diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java index b37413b91a2a..38c13ca345f6 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitShell.java @@ -16,12 +16,10 @@ import android.graphics.RectF; import android.os.Handler; import android.util.DisplayMetrics; import android.view.KeyEvent; -import android.view.MotionEvent; -import org.mozilla.gecko.TextSelectionHandle; +import org.libreoffice.canvas.SelectionHandle; import org.mozilla.gecko.gfx.ComposedTileLayer; import org.mozilla.gecko.gfx.LayerView; -import org.mozilla.gecko.gfx.SubTile; public class LOKitShell { @@ -151,7 +149,7 @@ public class LOKitShell { /** * Send change handle position event to LOKitThread. */ - public static void sendChangeHandlePositionEvent(TextSelectionHandle.HandleType handleType, PointF documentCoordinate) { + public static void sendChangeHandlePositionEvent(SelectionHandle.HandleType handleType, PointF documentCoordinate) { LOKitShell.sendEvent(new LOEvent(LOEvent.CHANGE_HANDLE_POSITION, handleType, documentCoordinate)); } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java index 1477730875cb..1da85f34be5c 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java @@ -5,7 +5,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.view.KeyEvent; -import org.mozilla.gecko.TextSelectionHandle; +import org.libreoffice.canvas.SelectionHandle; import org.mozilla.gecko.gfx.CairoImage; import org.mozilla.gecko.gfx.ComposedTileLayer; import org.mozilla.gecko.gfx.GeckoLayerClient; @@ -251,12 +251,12 @@ public class LOKitThread extends Thread { /** * Request a change of the handle position. */ - private void changeHandlePosition(TextSelectionHandle.HandleType handleType, PointF documentCoordinate) { - if (handleType == TextSelectionHandle.HandleType.MIDDLE) { + private void changeHandlePosition(SelectionHandle.HandleType handleType, PointF documentCoordinate) { + if (handleType == SelectionHandle.HandleType.MIDDLE) { mTileProvider.setTextSelectionReset(documentCoordinate); - } else if (handleType == TextSelectionHandle.HandleType.START) { + } else if (handleType == SelectionHandle.HandleType.START) { mTileProvider.setTextSelectionStart(documentCoordinate); - } else if (handleType == TextSelectionHandle.HandleType.END) { + } else if (handleType == SelectionHandle.HandleType.END) { mTileProvider.setTextSelectionEnd(documentCoordinate); } } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java index c3453bb751b5..3aaa2b204257 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -18,7 +18,6 @@ import android.widget.AdapterView; import android.widget.ListView; import org.libreoffice.overlay.TextCursorLayer; -import org.mozilla.gecko.TextSelection; import org.mozilla.gecko.ZoomConstraints; import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.LayerView; @@ -52,7 +51,6 @@ public class LibreOfficeMainActivity extends ActionBarActivity { private List<DocumentPartView> mDocumentPartView = new ArrayList<DocumentPartView>(); private DocumentPartViewListAdapter mDocumentPartViewListAdapter; private String mInputFile; - private TextSelection mTextSelection; private TextCursorLayer mTextCursorLayer; private File mTempFile = null; private LOAbout mAbout; @@ -162,10 +160,6 @@ public class LibreOfficeMainActivity extends ActionBarActivity { layerView.setInputConnectionHandler(new LOKitInputConnectionHandler()); mLayerClient.notifyReady(); - // create and register TextSelection in LayerView - mTextSelection = new TextSelection(mAppContext); - layerView.addLayer(mTextSelection); - // create TextCursorLayer mTextCursorLayer = new TextCursorLayer(mAppContext, layerView); } @@ -334,10 +328,6 @@ public class LibreOfficeMainActivity extends ActionBarActivity { alertDialog.show(); } - public TextSelection getTextSelection() { - return mTextSelection; - } - public TextCursorLayer getTextCursorLayer() { return mTextCursorLayer; } diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandle.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandle.java new file mode 100644 index 000000000000..9d244122e9a1 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandle.java @@ -0,0 +1,84 @@ +package org.libreoffice.canvas; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.Log; + +import org.libreoffice.LOKitShell; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; + +public abstract class SelectionHandle extends CommonCanvasElement { + private static final long MINIMUM_HANDLE_UPDATE_TIME = 50 * 1000000; + + public final RectF mDocumentPosition; + protected final Bitmap mBitmap; + protected final RectF mScreenPosition; + private final PointF mDragStartPoint = new PointF(); + private long mLastTime = 0; + private final PointF mDragDocumentPosition = new PointF(); + + public SelectionHandle(Bitmap bitmap) { + mBitmap = bitmap; + mScreenPosition = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + mDocumentPosition = new RectF(); + } + + protected static Bitmap getBitmapForDrawable(Context context, int drawableId) { + BitmapFactory.Options options = new BitmapFactory.Options(); + return BitmapFactory.decodeResource(context.getResources(), drawableId, options); + } + + @Override + public void onDraw(Canvas canvas) { + canvas.drawBitmap(mBitmap, mScreenPosition.left, mScreenPosition.top, null); + } + + @Override + public boolean onHitTest(float x, float y) { + return mScreenPosition.contains(x, y); + } + + public void reposition(float x, float y) { + mScreenPosition.offsetTo(x, y); + } + + public void dragStart(PointF point) { + mDragStartPoint.x = point.x; + mDragStartPoint.y = point.y; + mDragDocumentPosition.x = mDocumentPosition.left; + mDragDocumentPosition.y = mDocumentPosition.top; + } + + public void dragEnd(PointF point) { + //move(point.x, point.y); + } + + public void dragging(PointF point) { + long currentTime = System.nanoTime(); + if (currentTime - mLastTime > MINIMUM_HANDLE_UPDATE_TIME) { + mLastTime = currentTime; + move(point.x, point.y); + } + } + + private void move(float newX, float newY) { + ImmutableViewportMetrics viewportMetrics = LOKitShell.getLayerView().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/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleEnd.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleEnd.java new file mode 100644 index 000000000000..ec8b93c4681f --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleEnd.java @@ -0,0 +1,17 @@ +package org.libreoffice.canvas; + +import android.content.Context; +import android.graphics.Bitmap; + +import org.libreoffice.R; + +public class SelectionHandleEnd extends SelectionHandle { + public SelectionHandleEnd(Context context) { + super(getBitmapForDrawable(context, R.drawable.handle_end)); + } + + @Override + public HandleType getHandleType() { + return HandleType.END; + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java new file mode 100644 index 000000000000..7cbb847008af --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java @@ -0,0 +1,24 @@ +package org.libreoffice.canvas; + +import android.content.Context; +import android.graphics.Bitmap; + +import org.libreoffice.R; + +public class SelectionHandleMiddle extends SelectionHandle { + public SelectionHandleMiddle(Context context) { + super(getBitmapForDrawable(context, R.drawable.handle_middle)); + } + + @Override + public void reposition(float x, float y) { + super.reposition(x, y); + float offset = mScreenPosition.width() / 2.0f; + mScreenPosition.offset(-offset, 0); + } + + @Override + public HandleType getHandleType() { + return HandleType.MIDDLE; + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleStart.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleStart.java new file mode 100644 index 000000000000..aa1d3828b98a --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/canvas/SelectionHandleStart.java @@ -0,0 +1,24 @@ +package org.libreoffice.canvas; + +import android.content.Context; +import android.graphics.Bitmap; + +import org.libreoffice.R; + +public class SelectionHandleStart extends SelectionHandle { + public SelectionHandleStart(Context context) { + super(getBitmapForDrawable(context, R.drawable.handle_start)); + } + + @Override + public void reposition(float x, float y) { + super.reposition(x, y); + float offset = mScreenPosition.width(); + mScreenPosition.offset(-offset, 0); + } + + @Override + public HandleType getHandleType() { + return HandleType.START; + } +}
\ No newline at end of file diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorLayer.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorLayer.java index 9c4ab8120a3a..06622719882f 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorLayer.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorLayer.java @@ -14,6 +14,7 @@ import android.util.Log; import org.libreoffice.LOKitShell; import org.libreoffice.R; +import org.libreoffice.canvas.SelectionHandle; import org.mozilla.gecko.gfx.Layer; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.util.FloatUtils; @@ -144,7 +145,7 @@ public class TextCursorLayer extends Layer { } /** - * Hide the graphic selection on the overlay. + * Hide the graphic selection. */ public void hideGraphicSelection() { LOKitShell.getMainHandler().post(new Runnable() { @@ -164,6 +165,39 @@ public class TextCursorLayer extends Layer { } }); } + + /** + * Show the handle (of input type) on the overlay. + */ + public void showHandle(final SelectionHandle.HandleType type) { + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + mCursorView.showHandle(type); + } + }); + } + + /** + * Hide the handle (of input type). + */ + public void hideHandle(final SelectionHandle.HandleType type) { + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + mCursorView.hideHandle(type); + } + }); + } + + /** + * Position the handle (of input type) position to the input rectangle. + */ + public void positionHandle(final SelectionHandle.HandleType type, final RectF rectangle) { + LOKitShell.getMainHandler().post(new Runnable() { + public void run() { + mCursorView.positionHandle(type, rectangle); + } + }); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorView.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorView.java index 0eb97faeba80..3e83326f4a07 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorView.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/TextCursorView.java @@ -9,6 +9,8 @@ package org.libreoffice.overlay; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -20,7 +22,12 @@ import android.view.MotionEvent; import android.view.View; import org.libreoffice.LOKitShell; +import org.libreoffice.R; 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; @@ -54,6 +61,12 @@ public class TextCursorView extends View implements View.OnTouchListener { private LayerView mLayerView; + private SelectionHandle mHandleMiddle; + private SelectionHandle mHandleStart; + private SelectionHandle mHandleEnd; + + private SelectionHandle mDragHandle = null; + public TextCursorView(Context context) { super(context); } @@ -87,6 +100,10 @@ public class TextCursorView extends View implements View.OnTouchListener { postDelayed(cursorAnimation, CURSOR_BLINK_TIME); + mHandleMiddle = new SelectionHandleMiddle(getContext()); + mHandleStart = new SelectionHandleStart(getContext()); + mHandleEnd = new SelectionHandleEnd(getContext()); + mInitialized = true; } } @@ -140,6 +157,15 @@ public class TextCursorView extends View implements View.OnTouchListener { mCursorScaledPosition = convertToScreen(mCursorPosition, x, y, zoom); mCursorScaledPosition.right = mCursorScaledPosition.left + CURSOR_WIDTH; + RectF 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); @@ -148,7 +174,6 @@ public class TextCursorView extends View implements View.OnTouchListener { RectF scaledGraphicSelection = convertToScreen(mGraphicSelection.mRectangle, x, y, zoom); mGraphicSelection.reposition(scaledGraphicSelection); - invalidate(); } @@ -172,14 +197,18 @@ public class TextCursorView extends View implements View.OnTouchListener { if (mCursorVisible) { canvas.drawRect(mCursorScaledPosition, mCursorPaint); } + mHandleMiddle.draw(canvas); + mHandleStart.draw(canvas); + mHandleEnd.draw(canvas); + if (mSelectionsVisible) { for (RectF selection : mScaledSelections) { canvas.drawRect(selection, mSelectionPaint); } } - if (mGraphicSelection.isVisible()) { - mGraphicSelection.draw(canvas); - } + + mGraphicSelection.draw(canvas); + } /** @@ -250,33 +279,51 @@ public class TextCursorView extends View implements View.OnTouchListener { */ @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 - PointF startPosition = new PointF(event.getX(), event.getY()); - if (mGraphicSelection.contains(startPosition.x, startPosition.y)) { + if (mGraphicSelection.contains(point.x, point.y)) { mGraphicSelectionMove = true; - mGraphicSelection.dragStart(startPosition); + mGraphicSelection.dragStart(point); invalidate(); return true; } - return false; + } 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; - mGraphicSelection.dragEnd(new PointF(event.getX(), event.getY())); invalidate(); return true; + } else if (mDragHandle != null) { + mDragHandle.dragEnd(point); + mDragHandle = null; } } case MotionEvent.ACTION_MOVE: { if (mGraphicSelection.isVisible() && mGraphicSelectionMove) { - mGraphicSelection.dragging(new PointF(event.getX(), event.getY())); + mGraphicSelection.dragging(point); invalidate(); return true; + } else if (mDragHandle != null) { + mDragHandle.dragging(point); } } } @@ -286,6 +333,36 @@ public class TextCursorView extends View implements View.OnTouchListener { public void setLayerView(LayerView layerView) { this.mLayerView = layerView; } + + public void positionHandle(SelectionHandle.HandleType type, RectF position) { + SelectionHandle handle = getHandleForType(type); + 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); + handle.setVisible(false); + } + + public void showHandle(SelectionHandle.HandleType type) { + SelectionHandle handle = getHandleForType(type); + handle.setVisible(true); + } + + private SelectionHandle getHandleForType(SelectionHandle.HandleType type) { + switch(type) { + case START: + return mHandleStart; + case END: + return mHandleEnd; + case MIDDLE: + return mHandleMiddle; + } + return null; + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java deleted file mode 100644 index 359b7dd51a0f..000000000000 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelection.java +++ /dev/null @@ -1,137 +0,0 @@ -/* 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.mozilla.gecko; - -import android.app.Activity; -import android.graphics.RectF; -import android.util.Log; -import android.view.View; - -import org.libreoffice.LOKitShell; -import org.libreoffice.R; -import org.mozilla.gecko.gfx.Layer; -import org.mozilla.gecko.gfx.LayerView; -import org.mozilla.gecko.util.FloatUtils; - -import static org.mozilla.gecko.TextSelectionHandle.HandleType.MIDDLE; -import static org.mozilla.gecko.TextSelectionHandle.HandleType.START; - -/** - * TextSelection operates the text selection (start, middle and end) handles. It is a Layer implementation - * that intercepts viewport changes and repositions the text handles accordingly. - */ -public class TextSelection extends Layer { - private static final String LOGTAG = "GeckoTextSelection"; - - private final TextSelectionHandle mStartHandle; - private final TextSelectionHandle mMiddleHandle; - private final TextSelectionHandle mEndHandle; - - private float mViewLeft; - private float mViewTop; - private float mViewZoom; - - /** - * Construct the TextSelection. Context is needed to get the needed - * resources (views) to display all the handles and selections. - * @param context - the activity context - */ - public TextSelection(Activity context) { - mStartHandle = (TextSelectionHandle) context.findViewById(R.id.start_handle); - mMiddleHandle = (TextSelectionHandle) context.findViewById(R.id.middle_handle); - mEndHandle = (TextSelectionHandle) context.findViewById(R.id.end_handle); - - // Only register listeners if we have valid start/middle/end handles - if (mStartHandle == null || mMiddleHandle == null || mEndHandle == null) { - Log.e(LOGTAG, "Failed to initialize text selection because at least one handle is null"); - } - } - - /** - * Destroys created resources if any were created. - */ - void destroy() { - } - - /** - * Reposition the handles when draw happens. - */ - @Override - public void draw(final RenderContext context) { - // cache the relevant values from the context and bail out if they are the same. we do this - // because this draw function gets called a lot (once per compositor frame) and we want to - // avoid doing a lot of extra work in cases where it's not needed. - if (FloatUtils.fuzzyEquals(mViewLeft, context.viewport.left) - && FloatUtils.fuzzyEquals(mViewTop, context.viewport.top) - && FloatUtils.fuzzyEquals(mViewZoom, context.zoomFactor)) { - return; - } - mViewLeft = context.viewport.left; - mViewTop = context.viewport.top; - mViewZoom = context.zoomFactor; - - LOKitShell.getMainHandler().post(new Runnable() { - public void run() { - mStartHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); - mMiddleHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); - mEndHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor); - } - }); - } - - /** - * Shows the requested handle. - */ - public void showHandle(final TextSelectionHandle.HandleType handleType) { - LOKitShell.getMainHandler().post(new Runnable() { - public void run() { - TextSelectionHandle handle = getHandle(handleType); - - handle.setVisibility(View.VISIBLE); - - mViewLeft = 0.0f; - mViewTop = 0.0f; - mViewZoom = 0.0f; - } - }); - } - - /** - * Get instance of the requested handle type.. - */ - private TextSelectionHandle getHandle(TextSelectionHandle.HandleType handleType) { - if (handleType == START) { - return mStartHandle; - } else if (handleType == MIDDLE) { - return mMiddleHandle; - } else { - return mEndHandle; - } - } - - /** - * Hides the requested handle. - */ - public void hideHandle(final TextSelectionHandle.HandleType handleType) { - LOKitShell.getMainHandler().post(new Runnable() { - public void run() { - TextSelectionHandle handle = getHandle(handleType); - handle.setVisibility(View.GONE); - } - }); - } - - /** - * Position the handle requested handle to the input rectangle (expressed in document coordinates) - */ - public void positionHandle(final TextSelectionHandle.HandleType handleType, final RectF position) { - LOKitShell.getMainHandler().post(new Runnable() { - public void run() { - TextSelectionHandle handle = getHandle(handleType); - handle.positionFromGecko(position, false); - } - }); - } -} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java deleted file mode 100644 index aa4bec6d3e80..000000000000 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/TextSelectionHandle.java +++ /dev/null @@ -1,190 +0,0 @@ -/* 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.mozilla.gecko; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.PointF; -import android.graphics.RectF; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageView; -import android.widget.RelativeLayout; - -import org.json.JSONObject; -import org.libreoffice.LOKitShell; -import org.libreoffice.R; -import org.mozilla.gecko.gfx.ImmutableViewportMetrics; -import org.mozilla.gecko.gfx.LayerView; - -/** - * Custom image view used for showing the text selection handles. - */ -public class TextSelectionHandle extends ImageView implements View.OnTouchListener { - private static final String LOGTAG = TextSelectionHandle.class.getSimpleName(); - private long mLastTime = 0; - - // Minimum time lapsed between 2 handle updates - private static final long MINIMUM_HANDLE_UPDATE_TIME = 50 * 1000000; - - public enum HandleType { START, MIDDLE, END }; - - private final HandleType mHandleType; - private final int mWidth; - private final int mHeight; - private final int mShadow; - - private int mLeft; - private int mTop; - private boolean mIsRTL; - private PointF mPoint; - private PointF mReposition; - private int mTouchStartX; - private int mTouchStartY; - - private RelativeLayout.LayoutParams mLayoutParams; - - private static final int IMAGE_LEVEL_LTR = 0; - private static final int IMAGE_LEVEL_RTL = 1; - - public TextSelectionHandle(Context context, AttributeSet attrs) { - super(context, attrs); - setOnTouchListener(this); - - TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TextSelectionHandle); - int handleType = array.getInt(R.styleable.TextSelectionHandle_handleType, 0x01); - - switch (handleType) { - case 1: - mHandleType = HandleType.START; - break; - case 2: - mHandleType = HandleType.MIDDLE; - break; - case 3: - mHandleType = HandleType.END; - break; - default: - throw new RuntimeException("Unknown text handle id"); - } - - mIsRTL = false; - mPoint = new PointF(0.0f, 0.0f); - - mWidth = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_width); - mHeight = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_height); - mShadow = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_shadow); - } - - public boolean onTouch(View v, MotionEvent event) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - mTouchStartX = Math.round(event.getX()); - mTouchStartY = Math.round(event.getY()); - break; - } - case MotionEvent.ACTION_UP: { - mTouchStartX = 0; - mTouchStartY = 0; - break; - } - case MotionEvent.ACTION_MOVE: { - long currentTime = System.nanoTime(); - if (currentTime - mLastTime > MINIMUM_HANDLE_UPDATE_TIME) { - mLastTime = currentTime; - move(event.getX(), event.getY()); - } - break; - } - } - return true; - } - - private void move(float newX, float newY) { - LayerView layerView = LOKitShell.getLayerView(); - if (layerView == null) { - Log.e(LOGTAG, "Can't move selection because layerView is null"); - return; - } - - float newLeft = mLeft + newX - mTouchStartX; - float newTop = mTop + newY - mTouchStartY; - - // Send x coordinate on the right side of the start handle, left side of the end handle. - float left = (float) newLeft + adjustLeftForHandle(); - - PointF documentPoint = new PointF(left, newTop); - documentPoint = layerView.getLayerClient().convertViewPointToLayerPoint(documentPoint); - documentPoint.x += mReposition.x; - documentPoint.y += mReposition.y; - - LOKitShell.sendChangeHandlePositionEvent(mHandleType, documentPoint); - } - - /** - * Calculate the position just under (and centered horizontally) rectangle from the input rectangle. - * - * @param rectangle - input rectangle - * @return position just under the selection - */ - private PointF positionUnderSelection(RectF rectangle) { - return new PointF(rectangle.centerX(), rectangle.bottom); - } - - void positionFromGecko(RectF position, boolean rtl) { - LayerView layerView = LOKitShell.getLayerView(); - if (layerView == null) { - Log.e(LOGTAG, "Can't position handle because layerView is null"); - return; - } - - mPoint = positionUnderSelection(position); - mReposition = new PointF(position.left - mPoint.x, position.top - mPoint.y); - - if (mIsRTL != rtl) { - mIsRTL = rtl; - setImageLevel(mIsRTL ? IMAGE_LEVEL_RTL : IMAGE_LEVEL_LTR); - } - - ImmutableViewportMetrics metrics = layerView.getViewportMetrics(); - repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); - } - - void repositionWithViewport(float x, float y, float zoom) { - PointF viewPoint = new PointF(mPoint.x * zoom - x, - mPoint.y * zoom - y); - - mLeft = Math.round(viewPoint.x) - (int) adjustLeftForHandle(); - mTop = Math.round(viewPoint.y); - - setLayoutPosition(); - } - - private float adjustLeftForHandle() { - if (mHandleType.equals(HandleType.START)) - return mIsRTL ? mShadow : mWidth - mShadow; - else if (mHandleType.equals(HandleType.MIDDLE)) - return (float) ((mWidth - mShadow) / 2); - else - return mIsRTL ? mWidth - mShadow : mShadow; - } - - private void setLayoutPosition() { - if (mLayoutParams == null) { - mLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams(); - // Set negative right/bottom margins so that the handles can be dragged outside of - // the content area (if they are dragged to the left/top, the dyanmic margins set - // below will take care of that). - mLayoutParams.rightMargin = 0 - mWidth; - mLayoutParams.bottomMargin = 0 - mHeight; - } - - mLayoutParams.leftMargin = mLeft; - mLayoutParams.topMargin = mTop; - setLayoutParams(mLayoutParams); - } -} |