mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-04 02:09:35 +02:00
new style selection & selection cursors
This commit is contained in:
parent
ad6faeb64f
commit
943b01dc5d
23 changed files with 696 additions and 436 deletions
|
@ -8,6 +8,7 @@
|
||||||
* ComicBook plugin icon
|
* ComicBook plugin icon
|
||||||
* Updated Armenian localisation (by Yavruhrat, Marat Yavrumyan)
|
* Updated Armenian localisation (by Yavruhrat, Marat Yavrumyan)
|
||||||
* Added Korean intro text
|
* Added Korean intro text
|
||||||
|
* New style selection rendering
|
||||||
|
|
||||||
===== 2.4.7 (May 20, 2015) =====
|
===== 2.4.7 (May 20, 2015) =====
|
||||||
* Added Korean localisation
|
* Added Korean localisation
|
||||||
|
|
|
@ -151,8 +151,17 @@ class ProcessHyperlinkAction extends FBAndroidAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (soul instanceof ZLTextWordRegionSoul) {
|
} else if (soul instanceof ZLTextWordRegionSoul) {
|
||||||
DictionaryUtil.openWordInDictionary(
|
DictionaryUtil.openTextInDictionary(
|
||||||
BaseActivity, ((ZLTextWordRegionSoul)soul).Word, region
|
BaseActivity,
|
||||||
|
((ZLTextWordRegionSoul)soul).Word.getString(),
|
||||||
|
true,
|
||||||
|
region.getTop(),
|
||||||
|
region.getBottom(),
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
BaseActivity.outlineRegion(soul);
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
|
|
||||||
package org.geometerplus.android.fbreader;
|
package org.geometerplus.android.fbreader;
|
||||||
|
|
||||||
import org.geometerplus.fbreader.fbreader.FBReaderApp;
|
import org.geometerplus.fbreader.fbreader.*;
|
||||||
import org.geometerplus.fbreader.fbreader.FBView;
|
|
||||||
import org.geometerplus.android.fbreader.dict.DictionaryUtil;
|
import org.geometerplus.android.fbreader.dict.DictionaryUtil;
|
||||||
|
|
||||||
public class SelectionTranslateAction extends FBAndroidAction {
|
public class SelectionTranslateAction extends FBAndroidAction {
|
||||||
|
@ -31,13 +30,19 @@ public class SelectionTranslateAction extends FBAndroidAction {
|
||||||
@Override
|
@Override
|
||||||
protected void run(Object ... params) {
|
protected void run(Object ... params) {
|
||||||
final FBView fbview = Reader.getTextView();
|
final FBView fbview = Reader.getTextView();
|
||||||
|
final DictionaryHighlighting dictionaryHilite = new DictionaryHighlighting(fbview);
|
||||||
DictionaryUtil.openTextInDictionary(
|
DictionaryUtil.openTextInDictionary(
|
||||||
BaseActivity,
|
BaseActivity,
|
||||||
fbview.getSelectedSnippet().getText(),
|
fbview.getSelectedSnippet().getText(),
|
||||||
fbview.getCountOfSelectedWords() == 1,
|
fbview.getCountOfSelectedWords() == 1,
|
||||||
fbview.getSelectionStartY(),
|
fbview.getSelectionStartY(),
|
||||||
fbview.getSelectionEndY(),
|
fbview.getSelectionEndY(),
|
||||||
fbview.getSelectionSoul()
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
fbview.addHighlighting(dictionaryHilite);
|
||||||
|
Reader.getViewWidget().repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
fbview.clearSelection();
|
fbview.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ import org.geometerplus.zlibrary.core.options.ZLStringOption;
|
||||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||||
import org.geometerplus.zlibrary.core.util.XmlUtil;
|
import org.geometerplus.zlibrary.core.util.XmlUtil;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.view.ZLTextRegion;
|
|
||||||
import org.geometerplus.zlibrary.text.view.ZLTextWord;
|
import org.geometerplus.zlibrary.text.view.ZLTextWord;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidLibrary;
|
import org.geometerplus.zlibrary.ui.android.library.ZLAndroidLibrary;
|
||||||
|
@ -122,7 +121,7 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void open(String text, ZLTextRegion.Soul soulToSelect, FBReader fbreader, PopupFrameMetric frameMetrics);
|
abstract void open(String text, Runnable outliner, FBReader fbreader, PopupFrameMetric frameMetrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PlainPackageInfo extends PackageInfo {
|
private static class PlainPackageInfo extends PackageInfo {
|
||||||
|
@ -131,7 +130,7 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void open(String text, ZLTextRegion.Soul soulToSelect, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
void open(String text, Runnable outliner, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
||||||
final Intent intent = getDictionaryIntent(text);
|
final Intent intent = getDictionaryIntent(text);
|
||||||
try {
|
try {
|
||||||
final String id = getId();
|
final String id = getId();
|
||||||
|
@ -167,7 +166,7 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void open(String text, ZLTextRegion.Soul soulToSelect, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
void open(String text, Runnable outliner, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
||||||
final Intent intent = getDictionaryIntent(text);
|
final Intent intent = getDictionaryIntent(text);
|
||||||
try {
|
try {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
||||||
|
@ -176,7 +175,9 @@ public abstract class DictionaryUtil {
|
||||||
intent.putExtra("article.text.size.max", MAX_LENGTH_FOR_TOAST);
|
intent.putExtra("article.text.size.max", MAX_LENGTH_FOR_TOAST);
|
||||||
fbreader.startActivityForResult(intent, FBReader.REQUEST_DICTIONARY);
|
fbreader.startActivityForResult(intent, FBReader.REQUEST_DICTIONARY);
|
||||||
fbreader.overridePendingTransition(0, 0);
|
fbreader.overridePendingTransition(0, 0);
|
||||||
fbreader.outlineRegion(soulToSelect);
|
if (outliner != null) {
|
||||||
|
outliner.run();
|
||||||
|
}
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
fbreader.hideOutline();
|
fbreader.hideOutline();
|
||||||
installDictionaryIfNotInstalled(fbreader, this);
|
installDictionaryIfNotInstalled(fbreader, this);
|
||||||
|
@ -199,7 +200,7 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void open(String text, ZLTextRegion.Soul soulToSelect, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
void open(String text, Runnable outliner, FBReader fbreader, PopupFrameMetric frameMetrics) {
|
||||||
Flyout.showTranslation(fbreader, text, frameMetrics);
|
Flyout.showTranslation(fbreader, text, frameMetrics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,7 +456,7 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openTextInDictionary(final FBReader fbreader, String text, boolean singleWord, int selectionTop, int selectionBottom, final ZLTextRegion.Soul soulToSelect) {
|
public static void openTextInDictionary(final FBReader fbreader, String text, boolean singleWord, int selectionTop, int selectionBottom, final Runnable outliner) {
|
||||||
final String textToTranslate;
|
final String textToTranslate;
|
||||||
if (singleWord) {
|
if (singleWord) {
|
||||||
int start = 0;
|
int start = 0;
|
||||||
|
@ -478,17 +479,11 @@ public abstract class DictionaryUtil {
|
||||||
final PackageInfo info = getCurrentDictionaryInfo(singleWord);
|
final PackageInfo info = getCurrentDictionaryInfo(singleWord);
|
||||||
fbreader.runOnUiThread(new Runnable() {
|
fbreader.runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
info.open(textToTranslate, soulToSelect, fbreader, frameMetrics);
|
info.open(textToTranslate, outliner, fbreader, frameMetrics);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openWordInDictionary(FBReader fbreader, ZLTextWord word, ZLTextRegion region) {
|
|
||||||
openTextInDictionary(
|
|
||||||
fbreader, word.toString(), true, region.getTop(), region.getBottom(), region.getSoul()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void installDictionaryIfNotInstalled(final Activity activity, final PackageInfo info) {
|
public static void installDictionaryIfNotInstalled(final Activity activity, final PackageInfo info) {
|
||||||
if (PackageUtil.canBeStarted(activity, info.getDictionaryIntent("test"), false)) {
|
if (PackageUtil.canBeStarted(activity, info.getDictionaryIntent("test"), false)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -59,4 +59,9 @@ public final class BookmarkHighlighting extends ZLTextSimpleHighlighting {
|
||||||
final HighlightingStyle bmStyle = Collection.getHighlightingStyle(Bookmark.getStyleId());
|
final HighlightingStyle bmStyle = Collection.getHighlightingStyle(Bookmark.getStyleId());
|
||||||
return bmStyle != null ? bmStyle.getForegroundColor() : null;
|
return bmStyle != null ? bmStyle.getForegroundColor() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getOutlineColor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2015 FBReader.ORG Limited <contact@fbreader.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.fbreader.fbreader;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
import org.geometerplus.zlibrary.text.view.*;
|
||||||
|
|
||||||
|
public final class DictionaryHighlighting extends ZLTextSimpleHighlighting {
|
||||||
|
public DictionaryHighlighting(ZLTextView view) {
|
||||||
|
this(view, view.getSelectionHighlighting());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DictionaryHighlighting(ZLTextView view, ZLTextHighlighting selection) {
|
||||||
|
super(view, selection.getStartPosition(), selection.getEndPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getBackgroundColor() {
|
||||||
|
return View.getSelectionBackgroundColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getForegroundColor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getOutlineColor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.geometerplus.zlibrary.core.filesystem.ZLResourceFile;
|
||||||
import org.geometerplus.zlibrary.core.fonts.FontEntry;
|
import org.geometerplus.zlibrary.core.fonts.FontEntry;
|
||||||
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
||||||
import org.geometerplus.zlibrary.core.util.ZLColor;
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
import org.geometerplus.zlibrary.core.view.SelectionCursor;
|
||||||
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.model.ZLTextModel;
|
import org.geometerplus.zlibrary.text.model.ZLTextModel;
|
||||||
|
@ -158,10 +159,10 @@ public final class FBView extends ZLTextView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextSelectionCursor cursor = findSelectionCursor(x, y, maxSelectionDistance());
|
final SelectionCursor.Which cursor = findSelectionCursor(x, y, maxSelectionDistance());
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
|
myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
|
||||||
moveSelectionCursorTo(cursor, x, y, true);
|
moveSelectionCursorTo(cursor, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,9 +200,9 @@ public final class FBView extends ZLTextView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
|
final SelectionCursor.Which cursor = getSelectionCursorInMovement();
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
moveSelectionCursorTo(cursor, x, y, true);
|
moveSelectionCursorTo(cursor, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +230,8 @@ public final class FBView extends ZLTextView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
|
final SelectionCursor.Which cursor = getSelectionCursorInMovement();
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
releaseSelectionCursor();
|
releaseSelectionCursor();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -266,9 +267,9 @@ public final class FBView extends ZLTextView {
|
||||||
case startSelecting:
|
case startSelecting:
|
||||||
myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
|
myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
|
||||||
initSelection(x, y);
|
initSelection(x, y);
|
||||||
final ZLTextSelectionCursor cursor = findSelectionCursor(x, y);
|
final SelectionCursor.Which cursor = findSelectionCursor(x, y);
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
moveSelectionCursorTo(cursor, x, y, false);
|
moveSelectionCursorTo(cursor, x, y);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case selectSingleWord:
|
case selectSingleWord:
|
||||||
|
@ -300,9 +301,9 @@ public final class FBView extends ZLTextView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
|
final SelectionCursor.Which cursor = getSelectionCursorInMovement();
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
moveSelectionCursorTo(cursor, x, y, true);
|
moveSelectionCursorTo(cursor, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,8 +335,8 @@ public final class FBView extends ZLTextView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
|
final SelectionCursor.Which cursor = getSelectionCursorInMovement();
|
||||||
if (cursor != ZLTextSelectionCursor.None) {
|
if (cursor != null) {
|
||||||
releaseSelectionCursor();
|
releaseSelectionCursor();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.zlibrary.core.view;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
public final class HorizontalConvexHull implements Hull {
|
||||||
|
private final LinkedList<Rect> myRectangles = new LinkedList<Rect>();
|
||||||
|
|
||||||
|
public HorizontalConvexHull(Collection<Rect> rects) {
|
||||||
|
for (Rect r : rects) {
|
||||||
|
addRect(r);
|
||||||
|
}
|
||||||
|
normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRect(Rect rectangle) {
|
||||||
|
if (myRectangles.isEmpty()) {
|
||||||
|
myRectangles.add(new Rect(rectangle));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int top = rectangle.top;
|
||||||
|
final int bottom = rectangle.bottom;
|
||||||
|
for (ListIterator<Rect> iter = myRectangles.listIterator(); iter.hasNext(); ) {
|
||||||
|
Rect r = iter.next();
|
||||||
|
if (r.bottom <= top) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r.top >= bottom) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r.top < top) {
|
||||||
|
final Rect before = new Rect(r);
|
||||||
|
before.bottom = top;
|
||||||
|
r.top = top;
|
||||||
|
iter.previous();
|
||||||
|
iter.add(before);
|
||||||
|
iter.next();
|
||||||
|
}
|
||||||
|
if (r.bottom > bottom) {
|
||||||
|
final Rect after = new Rect(r);
|
||||||
|
after.top = bottom;
|
||||||
|
r.bottom = bottom;
|
||||||
|
iter.add(after);
|
||||||
|
}
|
||||||
|
r.left = Math.min(r.left, rectangle.left);
|
||||||
|
r.right = Math.max(r.right, rectangle.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Rect first = myRectangles.getFirst();
|
||||||
|
if (top < first.top) {
|
||||||
|
myRectangles.add(0, new Rect(rectangle.left, top, rectangle.right, Math.min(bottom, first.top)));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Rect last = myRectangles.getLast();
|
||||||
|
if (bottom > last.bottom) {
|
||||||
|
myRectangles.add(new Rect(rectangle.left, Math.max(top, last.bottom), rectangle.right, bottom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalize() {
|
||||||
|
Rect previous = null;
|
||||||
|
for (ListIterator<Rect> iter = myRectangles.listIterator(); iter.hasNext(); ) {
|
||||||
|
final Rect current = iter.next();
|
||||||
|
if (previous != null) {
|
||||||
|
if ((previous.left == current.left) && (previous.right == current.right)) {
|
||||||
|
previous.bottom = current.bottom;
|
||||||
|
iter.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((previous.bottom != current.top) &&
|
||||||
|
(current.left <= previous.right) &&
|
||||||
|
(previous.left <= current.right)) {
|
||||||
|
iter.previous();
|
||||||
|
iter.add(new Rect(
|
||||||
|
Math.max(previous.left, current.left),
|
||||||
|
previous.bottom,
|
||||||
|
Math.min(previous.right, current.right),
|
||||||
|
current.top
|
||||||
|
));
|
||||||
|
iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int distanceTo(int x, int y) {
|
||||||
|
int distance = Integer.MAX_VALUE;
|
||||||
|
for (Rect r : myRectangles) {
|
||||||
|
final int xd = r.left > x ? r.left - x : (r.right < x ? x - r.right : 0);
|
||||||
|
final int yd = r.top > y ? r.top - y : (r.bottom < y ? y - r.bottom : 0);
|
||||||
|
distance = Math.min(distance, Math.max(xd, yd));
|
||||||
|
if (distance == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBefore(int x, int y) {
|
||||||
|
for (Rect r : myRectangles) {
|
||||||
|
if (r.bottom < y || (r.top < y && r.right < x)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(ZLPaintContext context, int mode) {
|
||||||
|
if (mode == DrawMode.None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LinkedList<Rect> rectangles = new LinkedList<Rect>(myRectangles);
|
||||||
|
while (!rectangles.isEmpty()) {
|
||||||
|
final LinkedList<Rect> connected = new LinkedList<Rect>();
|
||||||
|
Rect previous = null;
|
||||||
|
for (final Iterator<Rect> iter = rectangles.iterator(); iter.hasNext(); ) {
|
||||||
|
final Rect current = iter.next();
|
||||||
|
if ((previous != null) &&
|
||||||
|
((previous.left > current.right) || (current.left > previous.right))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iter.remove();
|
||||||
|
connected.add(current);
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LinkedList<Integer> xList = new LinkedList<Integer>();
|
||||||
|
final LinkedList<Integer> yList = new LinkedList<Integer>();
|
||||||
|
int x = 0, xPrev = 0;
|
||||||
|
|
||||||
|
final ListIterator<Rect> iter = connected.listIterator();
|
||||||
|
Rect r = iter.next();
|
||||||
|
x = r.right + 2;
|
||||||
|
xList.add(x); yList.add(r.top);
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
xPrev = x;
|
||||||
|
r = iter.next();
|
||||||
|
x = r.right + 2;
|
||||||
|
if (x != xPrev) {
|
||||||
|
final int y = (x < xPrev) ? r.top + 2 : r.top;
|
||||||
|
xList.add(xPrev); yList.add(y);
|
||||||
|
xList.add(x); yList.add(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xList.add(x); yList.add(r.bottom + 2);
|
||||||
|
|
||||||
|
r = iter.previous();
|
||||||
|
x = r.left - 2;
|
||||||
|
xList.add(x); yList.add(r.bottom + 2);
|
||||||
|
while (iter.hasPrevious()) {
|
||||||
|
xPrev = x;
|
||||||
|
r = iter.previous();
|
||||||
|
x = r.left - 2;
|
||||||
|
if (x != xPrev) {
|
||||||
|
final int y = (x > xPrev) ? r.bottom : r.bottom + 2;
|
||||||
|
xList.add(xPrev); yList.add(y);
|
||||||
|
xList.add(x); yList.add(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xList.add(x); yList.add(r.top);
|
||||||
|
|
||||||
|
final int xs[] = new int[xList.size()];
|
||||||
|
final int ys[] = new int[yList.size()];
|
||||||
|
int count = 0;
|
||||||
|
for (int xx : xList) {
|
||||||
|
xs[count++] = xx;
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
for (int yy : yList) {
|
||||||
|
ys[count++] = yy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode & DrawMode.Fill) == DrawMode.Fill) {
|
||||||
|
context.fillPolygon(xs, ys);
|
||||||
|
}
|
||||||
|
if ((mode & DrawMode.Outline) == DrawMode.Outline) {
|
||||||
|
context.drawOutline(xs, ys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
src/org/geometerplus/zlibrary/core/view/Hull.java
Normal file
32
src/org/geometerplus/zlibrary/core/view/Hull.java
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.zlibrary.core.view;
|
||||||
|
|
||||||
|
public interface Hull {
|
||||||
|
interface DrawMode {
|
||||||
|
int None = 0;
|
||||||
|
int Outline = 1;
|
||||||
|
int Fill = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void draw(ZLPaintContext context, int mode);
|
||||||
|
int distanceTo(int x, int y);
|
||||||
|
boolean isBefore(int x, int y);
|
||||||
|
}
|
|
@ -17,40 +17,27 @@
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.core.view;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
||||||
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
|
||||||
public enum ZLTextSelectionCursor {
|
public abstract class SelectionCursor {
|
||||||
None,
|
public enum Which {
|
||||||
Left,
|
Left,
|
||||||
Right;
|
Right
|
||||||
|
}
|
||||||
|
|
||||||
private static int ourHeight;
|
public static void draw(ZLPaintContext context, Which which, int x, int y, ZLColor color) {
|
||||||
private static int ourWidth;
|
context.setFillColor(color);
|
||||||
private static int ourAccent;
|
|
||||||
|
|
||||||
private static void init() {
|
|
||||||
if (ourHeight == 0) {
|
|
||||||
final int dpi = ZLibrary.Instance().getDisplayDPI();
|
final int dpi = ZLibrary.Instance().getDisplayDPI();
|
||||||
ourAccent = dpi / 12;
|
final int unit = dpi / 120;
|
||||||
ourWidth = dpi / 6;
|
final int xCenter = which == Which.Left ? x - unit - 1 : x + unit + 1;
|
||||||
ourHeight = dpi / 4;
|
context.fillRectangle(xCenter - unit, y + dpi / 8, xCenter + unit, y - dpi / 8);
|
||||||
|
if (which == Which.Left) {
|
||||||
|
context.fillCircle(xCenter, y - dpi / 8, unit * 6);
|
||||||
|
} else {
|
||||||
|
context.fillCircle(xCenter, y + dpi / 8, unit * 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getHeight() {
|
|
||||||
init();
|
|
||||||
return ourHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getWidth() {
|
|
||||||
init();
|
|
||||||
return ourWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getAccent() {
|
|
||||||
init();
|
|
||||||
return ourAccent;
|
|
||||||
}
|
|
||||||
}
|
}
|
53
src/org/geometerplus/zlibrary/core/view/UnionHull.java
Normal file
53
src/org/geometerplus/zlibrary/core/view/UnionHull.java
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.zlibrary.core.view;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class UnionHull implements Hull {
|
||||||
|
private final List<Hull> myComponents;
|
||||||
|
|
||||||
|
public UnionHull(Hull ... components) {
|
||||||
|
myComponents = new ArrayList<Hull>(Arrays.asList(components));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(ZLPaintContext context, int mode) {
|
||||||
|
for (Hull h : myComponents) {
|
||||||
|
h.draw(context, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int distanceTo(int x, int y) {
|
||||||
|
int dist = Integer.MAX_VALUE;
|
||||||
|
for (Hull h : myComponents) {
|
||||||
|
dist = Math.min(dist, h.distanceTo(x, y));
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBefore(int x, int y) {
|
||||||
|
for (Hull h : myComponents) {
|
||||||
|
if (h.isBefore(x, y)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
55
src/org/geometerplus/zlibrary/text/view/HullUtil.java
Normal file
55
src/org/geometerplus/zlibrary/text/view/HullUtil.java
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.view.*;
|
||||||
|
|
||||||
|
abstract class HullUtil {
|
||||||
|
static Hull hull(ZLTextElementArea[] areas) {
|
||||||
|
return hull(Arrays.asList(areas));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Hull hull(List<ZLTextElementArea> areas) {
|
||||||
|
final List<Rect> rectangles0 = new ArrayList<Rect>(areas.size());
|
||||||
|
final List<Rect> rectangles1 = new ArrayList<Rect>(areas.size());
|
||||||
|
for (ZLTextElementArea a : areas) {
|
||||||
|
final Rect rect = new Rect(a.XStart, a.YStart, a.XEnd, a.YEnd);
|
||||||
|
if (a.ColumnIndex == 0) {
|
||||||
|
rectangles0.add(rect);
|
||||||
|
} else {
|
||||||
|
rectangles1.add(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rectangles0.isEmpty()) {
|
||||||
|
return new HorizontalConvexHull(rectangles1);
|
||||||
|
} else if (rectangles1.isEmpty()) {
|
||||||
|
return new HorizontalConvexHull(rectangles0);
|
||||||
|
} else {
|
||||||
|
return new UnionHull(
|
||||||
|
new HorizontalConvexHull(rectangles0),
|
||||||
|
new HorizontalConvexHull(rectangles1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ public final class ZLTextElementArea extends ZLTextFixedPosition {
|
||||||
public final int XEnd;
|
public final int XEnd;
|
||||||
public final int YStart;
|
public final int YStart;
|
||||||
public final int YEnd;
|
public final int YEnd;
|
||||||
|
public final int ColumnIndex;
|
||||||
|
|
||||||
final int Length;
|
final int Length;
|
||||||
final boolean AddHyphenationSign;
|
final boolean AddHyphenationSign;
|
||||||
|
@ -33,13 +34,14 @@ public final class ZLTextElementArea extends ZLTextFixedPosition {
|
||||||
|
|
||||||
private final boolean myIsLastInElement;
|
private final boolean myIsLastInElement;
|
||||||
|
|
||||||
ZLTextElementArea(int paragraphIndex, int elementIndex, int charIndex, int length, boolean lastInElement, boolean addHyphenationSign, boolean changeStyle, ZLTextStyle style, ZLTextElement element, int xStart, int xEnd, int yStart, int yEnd) {
|
ZLTextElementArea(int paragraphIndex, int elementIndex, int charIndex, int length, boolean lastInElement, boolean addHyphenationSign, boolean changeStyle, ZLTextStyle style, ZLTextElement element, int xStart, int xEnd, int yStart, int yEnd, int columnIndex) {
|
||||||
super(paragraphIndex, elementIndex, charIndex);
|
super(paragraphIndex, elementIndex, charIndex);
|
||||||
|
|
||||||
XStart = xStart;
|
XStart = xStart;
|
||||||
XEnd = xEnd;
|
XEnd = xEnd;
|
||||||
YStart = yStart;
|
YStart = yStart;
|
||||||
YEnd = yEnd;
|
YEnd = yEnd;
|
||||||
|
ColumnIndex = columnIndex;
|
||||||
|
|
||||||
Length = length;
|
Length = length;
|
||||||
myIsLastInElement = lastInElement;
|
myIsLastInElement = lastInElement;
|
||||||
|
|
|
@ -38,9 +38,10 @@ final class ZLTextElementAreaVector {
|
||||||
return myAreas.size();
|
return myAreas.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this unsafe method
|
public List<ZLTextElementArea> areas() {
|
||||||
public ZLTextElementArea get(int index) {
|
synchronized (myAreas) {
|
||||||
return myAreas.get(index);
|
return new ArrayList<ZLTextElementArea>(myAreas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZLTextElementArea getFirstArea() {
|
public ZLTextElementArea getFirstArea() {
|
||||||
|
@ -168,6 +169,28 @@ final class ZLTextElementAreaVector {
|
||||||
return bestRegion;
|
return bestRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class RegionPair {
|
||||||
|
ZLTextRegion Before;
|
||||||
|
ZLTextRegion After;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegionPair findRegionsPair(int x, int y, int columnIndex, ZLTextRegion.Filter filter) {
|
||||||
|
RegionPair pair = new RegionPair();
|
||||||
|
synchronized (myElementRegions) {
|
||||||
|
for (ZLTextRegion region : myElementRegions) {
|
||||||
|
if (filter.accepts(region)) {
|
||||||
|
if (region.isBefore(x, y, columnIndex)) {
|
||||||
|
pair.Before = region;
|
||||||
|
} else {
|
||||||
|
pair.After = region;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
|
||||||
protected ZLTextRegion nextRegion(ZLTextRegion currentRegion, ZLTextView.Direction direction, ZLTextRegion.Filter filter) {
|
protected ZLTextRegion nextRegion(ZLTextRegion currentRegion, ZLTextView.Direction direction, ZLTextRegion.Filter filter) {
|
||||||
synchronized (myElementRegions) {
|
synchronized (myElementRegions) {
|
||||||
if (myElementRegions.isEmpty()) {
|
if (myElementRegions.isEmpty()) {
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.util.ZLColor;
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
import org.geometerplus.zlibrary.core.view.Hull;
|
||||||
|
|
||||||
public abstract class ZLTextHighlighting implements Comparable<ZLTextHighlighting> {
|
public abstract class ZLTextHighlighting implements Comparable<ZLTextHighlighting> {
|
||||||
public abstract boolean isEmpty();
|
public abstract boolean isEmpty();
|
||||||
|
@ -31,6 +34,7 @@ public abstract class ZLTextHighlighting implements Comparable<ZLTextHighlightin
|
||||||
|
|
||||||
public abstract ZLColor getForegroundColor();
|
public abstract ZLColor getForegroundColor();
|
||||||
public abstract ZLColor getBackgroundColor();
|
public abstract ZLColor getBackgroundColor();
|
||||||
|
public abstract ZLColor getOutlineColor();
|
||||||
|
|
||||||
boolean intersects(ZLTextPage page) {
|
boolean intersects(ZLTextPage page) {
|
||||||
return
|
return
|
||||||
|
@ -48,6 +52,24 @@ public abstract class ZLTextHighlighting implements Comparable<ZLTextHighlightin
|
||||||
soul.compareTo(getEndPosition()) <= 0;
|
soul.compareTo(getEndPosition()) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Hull hull(ZLTextPage page) {
|
||||||
|
final ZLTextPosition startPosition = getStartPosition();
|
||||||
|
final ZLTextPosition endPosition = getEndPosition();
|
||||||
|
final List<ZLTextElementArea> areas = page.TextElementMap.areas();
|
||||||
|
int startIndex = 0;
|
||||||
|
int endIndex = 0;
|
||||||
|
for (int i = 0; i < areas.size(); ++i) {
|
||||||
|
final ZLTextElementArea a = areas.get(i);
|
||||||
|
if (i == startIndex && startPosition.compareTo(a) > 0) {
|
||||||
|
++startIndex;
|
||||||
|
} else if (endPosition.compareTo(a) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++endIndex;
|
||||||
|
}
|
||||||
|
return HullUtil.hull(areas.subList(startIndex, endIndex));
|
||||||
|
}
|
||||||
|
|
||||||
public int compareTo(ZLTextHighlighting highlighting) {
|
public int compareTo(ZLTextHighlighting highlighting) {
|
||||||
final int cmp = getStartPosition().compareTo(highlighting.getStartPosition());
|
final int cmp = getStartPosition().compareTo(highlighting.getStartPosition());
|
||||||
return cmp != 0 ? cmp : getEndPosition().compareTo(highlighting.getEndPosition());
|
return cmp != 0 ? cmp : getEndPosition().compareTo(highlighting.getEndPosition());
|
||||||
|
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
|
||||||
|
|
||||||
class ZLTextHorizontalConvexHull {
|
|
||||||
private final LinkedList<Rectangle> myRectangles = new LinkedList<Rectangle>();
|
|
||||||
|
|
||||||
ZLTextHorizontalConvexHull(ZLTextElementArea[] textAreas) {
|
|
||||||
for (ZLTextElementArea area : textAreas) {
|
|
||||||
addArea(area);
|
|
||||||
}
|
|
||||||
normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addArea(ZLTextElementArea area) {
|
|
||||||
if (myRectangles.isEmpty()) {
|
|
||||||
myRectangles.add(new Rectangle(area.XStart, area.XEnd, area.YStart, area.YEnd));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final int top = area.YStart;
|
|
||||||
final int bottom = area.YEnd;
|
|
||||||
for (ListIterator<Rectangle> iter = myRectangles.listIterator(); iter.hasNext(); ) {
|
|
||||||
Rectangle r = iter.next();
|
|
||||||
if (r.Bottom <= top) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (r.Top >= bottom) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (r.Top < top) {
|
|
||||||
final Rectangle before = new Rectangle(r);
|
|
||||||
before.Bottom = top;
|
|
||||||
r.Top = top;
|
|
||||||
iter.previous();
|
|
||||||
iter.add(before);
|
|
||||||
iter.next();
|
|
||||||
}
|
|
||||||
if (r.Bottom > bottom) {
|
|
||||||
final Rectangle after = new Rectangle(r);
|
|
||||||
after.Top = bottom;
|
|
||||||
r.Bottom = bottom;
|
|
||||||
iter.add(after);
|
|
||||||
}
|
|
||||||
r.Left = Math.min(r.Left, area.XStart);
|
|
||||||
r.Right = Math.max(r.Right, area.XEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Rectangle first = myRectangles.getFirst();
|
|
||||||
if (top < first.Top) {
|
|
||||||
myRectangles.add(0, new Rectangle(area.XStart, area.XEnd, top, Math.min(bottom, first.Top)));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Rectangle last = myRectangles.getLast();
|
|
||||||
if (bottom > last.Bottom) {
|
|
||||||
myRectangles.add(new Rectangle(area.XStart, area.XEnd, Math.max(top, last.Bottom), bottom));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void normalize() {
|
|
||||||
Rectangle previous = null;
|
|
||||||
for (ListIterator<Rectangle> iter = myRectangles.listIterator(); iter.hasNext(); ) {
|
|
||||||
final Rectangle current = iter.next();
|
|
||||||
if (previous != null) {
|
|
||||||
if ((previous.Left == current.Left) && (previous.Right == current.Right)) {
|
|
||||||
previous.Bottom = current.Bottom;
|
|
||||||
iter.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((previous.Bottom != current.Top) &&
|
|
||||||
(current.Left <= previous.Right) &&
|
|
||||||
(previous.Left <= current.Right)) {
|
|
||||||
iter.previous();
|
|
||||||
iter.add(new Rectangle(
|
|
||||||
Math.max(previous.Left, current.Left),
|
|
||||||
Math.min(previous.Right, current.Right),
|
|
||||||
previous.Bottom,
|
|
||||||
current.Top
|
|
||||||
));
|
|
||||||
iter.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int distanceTo(int x, int y) {
|
|
||||||
int distance = Integer.MAX_VALUE;
|
|
||||||
for (Rectangle r : myRectangles) {
|
|
||||||
final int xd = (r.Left > x) ? r.Left - x : ((r.Right < x) ? x - r.Right : 0);
|
|
||||||
final int yd = (r.Top > y) ? r.Top - y : ((r.Bottom < y) ? y - r.Bottom : 0);
|
|
||||||
distance = Math.min(distance, Math.max(xd, yd));
|
|
||||||
if (distance == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(ZLPaintContext context) {
|
|
||||||
final LinkedList<Rectangle> rectangles = new LinkedList<Rectangle>(myRectangles);
|
|
||||||
while (!rectangles.isEmpty()) {
|
|
||||||
final LinkedList<Rectangle> connected = new LinkedList<Rectangle>();
|
|
||||||
Rectangle previous = null;
|
|
||||||
for (final Iterator<Rectangle> iter = rectangles.iterator(); iter.hasNext(); ) {
|
|
||||||
final Rectangle current = iter.next();
|
|
||||||
if ((previous != null) &&
|
|
||||||
((previous.Left > current.Right) || (current.Left > previous.Right))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
iter.remove();
|
|
||||||
connected.add(current);
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
|
|
||||||
final LinkedList<Integer> xList = new LinkedList<Integer>();
|
|
||||||
final LinkedList<Integer> yList = new LinkedList<Integer>();
|
|
||||||
int x = 0, xPrev = 0;
|
|
||||||
|
|
||||||
final ListIterator<Rectangle> iter = connected.listIterator();
|
|
||||||
Rectangle r = iter.next();
|
|
||||||
x = r.Right + 2;
|
|
||||||
xList.add(x); yList.add(r.Top);
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
xPrev = x;
|
|
||||||
r = iter.next();
|
|
||||||
x = r.Right + 2;
|
|
||||||
if (x != xPrev) {
|
|
||||||
final int y = (x < xPrev) ? r.Top + 2 : r.Top;
|
|
||||||
xList.add(xPrev); yList.add(y);
|
|
||||||
xList.add(x); yList.add(y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xList.add(x); yList.add(r.Bottom + 2);
|
|
||||||
|
|
||||||
r = iter.previous();
|
|
||||||
x = r.Left - 2;
|
|
||||||
xList.add(x); yList.add(r.Bottom + 2);
|
|
||||||
while (iter.hasPrevious()) {
|
|
||||||
xPrev = x;
|
|
||||||
r = iter.previous();
|
|
||||||
x = r.Left - 2;
|
|
||||||
if (x != xPrev) {
|
|
||||||
final int y = (x > xPrev) ? r.Bottom : r.Bottom + 2;
|
|
||||||
xList.add(xPrev); yList.add(y);
|
|
||||||
xList.add(x); yList.add(y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xList.add(x); yList.add(r.Top);
|
|
||||||
|
|
||||||
final int xs[] = new int[xList.size()];
|
|
||||||
final int ys[] = new int[yList.size()];
|
|
||||||
int count = 0;
|
|
||||||
for (int xx : xList) {
|
|
||||||
xs[count++] = xx;
|
|
||||||
}
|
|
||||||
count = 0;
|
|
||||||
for (int yy : yList) {
|
|
||||||
ys[count++] = yy;
|
|
||||||
}
|
|
||||||
context.drawOutline(xs, ys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Rectangle {
|
|
||||||
int Left;
|
|
||||||
int Right;
|
|
||||||
int Top;
|
|
||||||
int Bottom;
|
|
||||||
|
|
||||||
Rectangle(int left, int right, int top, int bottom) {
|
|
||||||
Left = left;
|
|
||||||
Right = right;
|
|
||||||
Top = top;
|
|
||||||
Bottom = bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle(Rectangle orig) {
|
|
||||||
Left = orig.Left;
|
|
||||||
Right = orig.Right;
|
|
||||||
Top = orig.Top;
|
|
||||||
Bottom = orig.Bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,4 +35,9 @@ class ZLTextManualHighlighting extends ZLTextSimpleHighlighting {
|
||||||
public ZLColor getForegroundColor() {
|
public ZLColor getForegroundColor() {
|
||||||
return View.getHighlightingForegroundColor();
|
return View.getHighlightingForegroundColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getOutlineColor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.view.Hull;
|
||||||
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
||||||
|
|
||||||
public final class ZLTextRegion {
|
public final class ZLTextRegion {
|
||||||
|
@ -139,7 +140,8 @@ public final class ZLTextRegion {
|
||||||
private ZLTextElementArea[] myAreas;
|
private ZLTextElementArea[] myAreas;
|
||||||
private final int myFromIndex;
|
private final int myFromIndex;
|
||||||
private int myToIndex;
|
private int myToIndex;
|
||||||
private ZLTextHorizontalConvexHull myHull;
|
private Hull myHull;
|
||||||
|
private Hull myHull0; // convex hull for left page column
|
||||||
|
|
||||||
ZLTextRegion(Soul soul, List<ZLTextElementArea> list, int fromIndex) {
|
ZLTextRegion(Soul soul, List<ZLTextElementArea> list, int fromIndex) {
|
||||||
mySoul = soul;
|
mySoul = soul;
|
||||||
|
@ -157,7 +159,7 @@ public final class ZLTextRegion {
|
||||||
return mySoul;
|
return mySoul;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZLTextElementArea[] textAreas() {
|
ZLTextElementArea[] textAreas() {
|
||||||
if (myAreas == null || myAreas.length != myToIndex - myFromIndex) {
|
if (myAreas == null || myAreas.length != myToIndex - myFromIndex) {
|
||||||
synchronized (myAreaList) {
|
synchronized (myAreaList) {
|
||||||
myAreas = new ZLTextElementArea[myToIndex - myFromIndex];
|
myAreas = new ZLTextElementArea[myToIndex - myFromIndex];
|
||||||
|
@ -168,12 +170,24 @@ public final class ZLTextRegion {
|
||||||
}
|
}
|
||||||
return myAreas;
|
return myAreas;
|
||||||
}
|
}
|
||||||
private ZLTextHorizontalConvexHull convexHull() {
|
Hull hull() {
|
||||||
if (myHull == null) {
|
if (myHull == null) {
|
||||||
myHull = new ZLTextHorizontalConvexHull(textAreas());
|
myHull = HullUtil.hull(textAreas());
|
||||||
}
|
}
|
||||||
return myHull;
|
return myHull;
|
||||||
}
|
}
|
||||||
|
Hull hull0() {
|
||||||
|
if (myHull0 == null) {
|
||||||
|
final List<ZLTextElementArea> column0 = new ArrayList<ZLTextElementArea>();
|
||||||
|
for (ZLTextElementArea a : textAreas()) {
|
||||||
|
if (a.ColumnIndex == 0) {
|
||||||
|
column0.add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myHull0 = HullUtil.hull(column0);
|
||||||
|
}
|
||||||
|
return myHull0;
|
||||||
|
}
|
||||||
|
|
||||||
ZLTextElementArea getFirstArea() {
|
ZLTextElementArea getFirstArea() {
|
||||||
return textAreas()[0];
|
return textAreas()[0];
|
||||||
|
@ -208,12 +222,42 @@ public final class ZLTextRegion {
|
||||||
return getLastArea().YEnd;
|
return getLastArea().YEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(ZLPaintContext context) {
|
int distanceTo(int x, int y) {
|
||||||
convexHull().draw(context);
|
return hull().distanceTo(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
int distanceTo(int x, int y) {
|
boolean isBefore(int x, int y, int columnIndex) {
|
||||||
return convexHull().distanceTo(x, y);
|
switch (columnIndex) {
|
||||||
|
default:
|
||||||
|
case -1:
|
||||||
|
return hull().isBefore(x, y);
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
int count0 = 0;
|
||||||
|
int count1 = 0;
|
||||||
|
for (ZLTextElementArea area : textAreas()) {
|
||||||
|
if (area.ColumnIndex == 0) {
|
||||||
|
++count0;
|
||||||
|
} else {
|
||||||
|
++count1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count0 == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (count1 == 0) {
|
||||||
|
return hull().isBefore(x, y);
|
||||||
|
} else {
|
||||||
|
return hull0().isBefore(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
for (ZLTextElementArea area : textAreas()) {
|
||||||
|
if (area.ColumnIndex == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hull().isBefore(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isAtRightOf(ZLTextRegion other) {
|
boolean isAtRightOf(ZLTextRegion other) {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.util.ZLColor;
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
|
import org.geometerplus.zlibrary.core.view.SelectionCursor;
|
||||||
|
|
||||||
class ZLTextSelection extends ZLTextHighlighting {
|
class ZLTextSelection extends ZLTextHighlighting {
|
||||||
static class Point {
|
static class Point {
|
||||||
|
@ -37,7 +38,7 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
private ZLTextRegion.Soul myLeftMostRegionSoul;
|
private ZLTextRegion.Soul myLeftMostRegionSoul;
|
||||||
private ZLTextRegion.Soul myRightMostRegionSoul;
|
private ZLTextRegion.Soul myRightMostRegionSoul;
|
||||||
|
|
||||||
private ZLTextSelectionCursor myCursorInMovement = ZLTextSelectionCursor.None;
|
private SelectionCursor.Which myCursorInMovement = null;
|
||||||
private final Point myCursorInMovementPoint = new Point(-1, -1);
|
private final Point myCursorInMovementPoint = new Point(-1, -1);
|
||||||
|
|
||||||
private Scroller myScroller;
|
private Scroller myScroller;
|
||||||
|
@ -46,10 +47,6 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
myView = view;
|
myView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextRegion.Soul getSoul() {
|
|
||||||
return myLeftMostRegionSoul != null && myLeftMostRegionSoul.equals(myRightMostRegionSoul) ? myLeftMostRegionSoul : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return myLeftMostRegionSoul == null;
|
return myLeftMostRegionSoul == null;
|
||||||
|
@ -63,17 +60,17 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
stop();
|
stop();
|
||||||
myLeftMostRegionSoul = null;
|
myLeftMostRegionSoul = null;
|
||||||
myRightMostRegionSoul = null;
|
myRightMostRegionSoul = null;
|
||||||
myCursorInMovement = ZLTextSelectionCursor.None;
|
myCursorInMovement = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCursorInMovement(ZLTextSelectionCursor cursor, int x, int y) {
|
void setCursorInMovement(SelectionCursor.Which which, int x, int y) {
|
||||||
myCursorInMovement = cursor;
|
myCursorInMovement = which;
|
||||||
myCursorInMovementPoint.X = x;
|
myCursorInMovementPoint.X = x;
|
||||||
myCursorInMovementPoint.Y = y;
|
myCursorInMovementPoint.Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextSelectionCursor getCursorInMovement() {
|
SelectionCursor.Which getCursorInMovement() {
|
||||||
return myCursorInMovement;
|
return myCursorInMovement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +93,7 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
myCursorInMovement = ZLTextSelectionCursor.None;
|
myCursorInMovement = null;
|
||||||
if (myScroller != null) {
|
if (myScroller != null) {
|
||||||
myScroller.stop();
|
myScroller.stop();
|
||||||
myScroller = null;
|
myScroller = null;
|
||||||
|
@ -120,7 +117,8 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
myScroller = new Scroller(page, false, x, y);
|
myScroller = new Scroller(page, false, x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (lastArea != null && y + ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2 > lastArea.YEnd) {
|
//} else if (lastArea != null && y + ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2 > lastArea.YEnd) {
|
||||||
|
} else if (lastArea != null && y > lastArea.YEnd) {
|
||||||
if (myScroller != null && !myScroller.scrollsForward()) {
|
if (myScroller != null && !myScroller.scrollsForward()) {
|
||||||
myScroller.stop();
|
myScroller.stop();
|
||||||
myScroller = null;
|
myScroller = null;
|
||||||
|
@ -141,21 +139,40 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextRegion region = myView.findRegion(x, y, myView.maxSelectionDistance(), ZLTextRegion.AnyRegionFilter);
|
ZLTextRegion region = myView.findRegion(x, y, myView.maxSelectionDistance(), ZLTextRegion.AnyRegionFilter);
|
||||||
if (region == null && myScroller != null) {
|
if (region == null) {
|
||||||
region = myView.findRegion(x, y, ZLTextRegion.AnyRegionFilter);
|
final ZLTextElementAreaVector.RegionPair pair =
|
||||||
|
myView.findRegionsPair(x, y, ZLTextRegion.AnyRegionFilter);
|
||||||
|
if (pair.Before != null || pair.After != null) {
|
||||||
|
final ZLTextRegion.Soul base =
|
||||||
|
myCursorInMovement == SelectionCursor.Which.Right
|
||||||
|
? myLeftMostRegionSoul : myRightMostRegionSoul;
|
||||||
|
if (pair.Before != null) {
|
||||||
|
if (base.compareTo(pair.Before.getSoul()) <= 0) {
|
||||||
|
region = pair.Before;
|
||||||
|
} else {
|
||||||
|
region = pair.After;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (base.compareTo(pair.After.getSoul()) >= 0) {
|
||||||
|
region = pair.After;
|
||||||
|
} else {
|
||||||
|
region = pair.Before;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (region == null) {
|
if (region == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextRegion.Soul soul = region.getSoul();
|
final ZLTextRegion.Soul soul = region.getSoul();
|
||||||
if (myCursorInMovement == ZLTextSelectionCursor.Right) {
|
if (myCursorInMovement == SelectionCursor.Which.Right) {
|
||||||
if (myLeftMostRegionSoul.compareTo(soul) <= 0) {
|
if (myLeftMostRegionSoul.compareTo(soul) <= 0) {
|
||||||
myRightMostRegionSoul = soul;
|
myRightMostRegionSoul = soul;
|
||||||
} else {
|
} else {
|
||||||
myRightMostRegionSoul = myLeftMostRegionSoul;
|
myRightMostRegionSoul = myLeftMostRegionSoul;
|
||||||
myLeftMostRegionSoul = soul;
|
myLeftMostRegionSoul = soul;
|
||||||
myCursorInMovement = ZLTextSelectionCursor.Left;
|
myCursorInMovement = SelectionCursor.Which.Left;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (myRightMostRegionSoul.compareTo(soul) >= 0) {
|
if (myRightMostRegionSoul.compareTo(soul) >= 0) {
|
||||||
|
@ -163,11 +180,11 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
} else {
|
} else {
|
||||||
myLeftMostRegionSoul = myRightMostRegionSoul;
|
myLeftMostRegionSoul = myRightMostRegionSoul;
|
||||||
myRightMostRegionSoul = soul;
|
myRightMostRegionSoul = soul;
|
||||||
myCursorInMovement = ZLTextSelectionCursor.Right;
|
myCursorInMovement = SelectionCursor.Which.Right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myCursorInMovement == ZLTextSelectionCursor.Right) {
|
if (myCursorInMovement == SelectionCursor.Which.Right) {
|
||||||
if (hasPartAfterPage(page)) {
|
if (hasPartAfterPage(page)) {
|
||||||
myView.turnPage(true, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
|
myView.turnPage(true, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
|
||||||
myView.Application.getViewWidget().reset();
|
myView.Application.getViewWidget().reset();
|
||||||
|
@ -276,6 +293,11 @@ class ZLTextSelection extends ZLTextHighlighting {
|
||||||
return myView.getSelectionForegroundColor();
|
return myView.getSelectionForegroundColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZLColor getOutlineColor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private class Scroller implements Runnable {
|
private class Scroller implements Runnable {
|
||||||
private final ZLTextPage myPage;
|
private final ZLTextPage myPage;
|
||||||
private final boolean myScrollForward;
|
private final boolean myScrollForward;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.view.HorizontalConvexHull;
|
||||||
|
|
||||||
public abstract class ZLTextSimpleHighlighting extends ZLTextHighlighting {
|
public abstract class ZLTextSimpleHighlighting extends ZLTextHighlighting {
|
||||||
protected final ZLTextView View;
|
protected final ZLTextView View;
|
||||||
private final ZLTextPosition myStartPosition;
|
private final ZLTextPosition myStartPosition;
|
||||||
|
|
|
@ -21,13 +21,15 @@ package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import android.util.FloatMath;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.application.ZLApplication;
|
import org.geometerplus.zlibrary.core.application.ZLApplication;
|
||||||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||||
import org.geometerplus.zlibrary.core.image.ZLImageData;
|
import org.geometerplus.zlibrary.core.image.ZLImageData;
|
||||||
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
import org.geometerplus.zlibrary.core.library.ZLibrary;
|
||||||
import org.geometerplus.zlibrary.core.util.RationalNumber;
|
import org.geometerplus.zlibrary.core.util.RationalNumber;
|
||||||
import org.geometerplus.zlibrary.core.util.ZLColor;
|
import org.geometerplus.zlibrary.core.util.ZLColor;
|
||||||
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
import org.geometerplus.zlibrary.core.view.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.model.*;
|
import org.geometerplus.zlibrary.text.model.*;
|
||||||
import org.geometerplus.zlibrary.text.hyphenation.*;
|
import org.geometerplus.zlibrary.text.hyphenation.*;
|
||||||
|
@ -327,13 +329,9 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void moveSelectionCursorTo(ZLTextSelectionCursor cursor, int x, int y, boolean inMovement) {
|
protected void moveSelectionCursorTo(SelectionCursor.Which which, int x, int y) {
|
||||||
if (inMovement) {
|
|
||||||
y -= ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2;
|
|
||||||
} else {
|
|
||||||
y -= getTextStyleCollection().getBaseStyle().getFontSize() / 2;
|
y -= getTextStyleCollection().getBaseStyle().getFontSize() / 2;
|
||||||
}
|
mySelection.setCursorInMovement(which, x, y);
|
||||||
mySelection.setCursorInMovement(cursor, x, y);
|
|
||||||
mySelection.expandTo(myCurrentPage, x, y);
|
mySelection.expandTo(myCurrentPage, x, y);
|
||||||
Application.getViewWidget().reset();
|
Application.getViewWidget().reset();
|
||||||
Application.getViewWidget().repaint();
|
Application.getViewWidget().repaint();
|
||||||
|
@ -345,104 +343,68 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
Application.getViewWidget().repaint();
|
Application.getViewWidget().repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ZLTextSelectionCursor getSelectionCursorInMovement() {
|
protected SelectionCursor.Which getSelectionCursorInMovement() {
|
||||||
return mySelection.getCursorInMovement();
|
return mySelection.getCursorInMovement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZLTextSelection.Point getSelectionCursorPoint(ZLTextPage page, ZLTextSelectionCursor cursor) {
|
private ZLTextSelection.Point getSelectionCursorPoint(ZLTextPage page, SelectionCursor.Which which) {
|
||||||
if (cursor == ZLTextSelectionCursor.None) {
|
if (which == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor == mySelection.getCursorInMovement()) {
|
if (which == mySelection.getCursorInMovement()) {
|
||||||
return mySelection.getCursorInMovementPoint();
|
return mySelection.getCursorInMovementPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor == ZLTextSelectionCursor.Left) {
|
if (which == SelectionCursor.Which.Left) {
|
||||||
if (mySelection.hasPartBeforePage(page)) {
|
if (mySelection.hasPartBeforePage(page)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final ZLTextElementArea selectionStartArea = mySelection.getStartArea(page);
|
final ZLTextElementArea area = mySelection.getStartArea(page);
|
||||||
if (selectionStartArea != null) {
|
if (area != null) {
|
||||||
return new ZLTextSelection.Point(selectionStartArea.XStart, selectionStartArea.YEnd);
|
return new ZLTextSelection.Point(area.XStart, (area.YStart + area.YEnd) / 2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mySelection.hasPartAfterPage(page)) {
|
if (mySelection.hasPartAfterPage(page)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final ZLTextElementArea selectionEndArea = mySelection.getEndArea(page);
|
final ZLTextElementArea area = mySelection.getEndArea(page);
|
||||||
if (selectionEndArea != null) {
|
if (area != null) {
|
||||||
return new ZLTextSelection.Point(selectionEndArea.XEnd, selectionEndArea.YEnd);
|
return new ZLTextSelection.Point(area.XEnd, (area.YStart + area.YEnd) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int distanceToCursor(int x, int y, ZLTextSelection.Point cursorPoint) {
|
private float distanceToCursor(int x, int y, SelectionCursor.Which which) {
|
||||||
if (cursorPoint == null) {
|
final ZLTextSelection.Point point = getSelectionCursorPoint(myCurrentPage, which);
|
||||||
return Integer.MAX_VALUE;
|
return point != null ? FloatMath.hypot(x - point.X, y - point.Y) : Float.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int dX, dY;
|
protected SelectionCursor.Which findSelectionCursor(int x, int y) {
|
||||||
|
return findSelectionCursor(x, y, Float.MAX_VALUE);
|
||||||
final int w = ZLTextSelectionCursor.getWidth() / 2;
|
|
||||||
if (x < cursorPoint.X - w) {
|
|
||||||
dX = cursorPoint.X - w - x;
|
|
||||||
} else if (x > cursorPoint.X + w) {
|
|
||||||
dX = x - cursorPoint.X - w;
|
|
||||||
} else {
|
|
||||||
dX = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final int h = ZLTextSelectionCursor.getHeight();
|
protected SelectionCursor.Which findSelectionCursor(int x, int y, float maxDistance) {
|
||||||
if (y < cursorPoint.Y) {
|
|
||||||
dY = cursorPoint.Y - y;
|
|
||||||
} else if (y > cursorPoint.Y + h) {
|
|
||||||
dY = y - cursorPoint.Y - h;
|
|
||||||
} else {
|
|
||||||
dY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.max(dX, dY);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ZLTextSelectionCursor findSelectionCursor(int x, int y) {
|
|
||||||
return findSelectionCursor(x, y, Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ZLTextSelectionCursor findSelectionCursor(int x, int y, int maxDistance) {
|
|
||||||
if (mySelection.isEmpty()) {
|
if (mySelection.isEmpty()) {
|
||||||
return ZLTextSelectionCursor.None;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int leftDistance = distanceToCursor(
|
final float leftDistance = distanceToCursor(x, y, SelectionCursor.Which.Left);
|
||||||
x, y, getSelectionCursorPoint(myCurrentPage, ZLTextSelectionCursor.Left)
|
final float rightDistance = distanceToCursor(x, y, SelectionCursor.Which.Right);
|
||||||
);
|
|
||||||
final int rightDistance = distanceToCursor(
|
|
||||||
x, y, getSelectionCursorPoint(myCurrentPage, ZLTextSelectionCursor.Right)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (rightDistance < leftDistance) {
|
if (rightDistance < leftDistance) {
|
||||||
return rightDistance <= maxDistance ? ZLTextSelectionCursor.Right : ZLTextSelectionCursor.None;
|
return rightDistance <= maxDistance ? SelectionCursor.Which.Right : null;
|
||||||
} else {
|
} else {
|
||||||
return leftDistance <= maxDistance ? ZLTextSelectionCursor.Left : ZLTextSelectionCursor.None;
|
return leftDistance <= maxDistance ? SelectionCursor.Which.Left : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawSelectionCursor(ZLPaintContext context, ZLTextSelection.Point pt) {
|
private void drawSelectionCursor(ZLPaintContext context, ZLTextPage page, SelectionCursor.Which which) {
|
||||||
if (pt == null) {
|
final ZLTextSelection.Point pt = getSelectionCursorPoint(page, which);
|
||||||
return;
|
if (pt != null) {
|
||||||
|
SelectionCursor.draw(context, which, pt.X, pt.Y, getSelectionBackgroundColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
final int w = ZLTextSelectionCursor.getWidth() / 2;
|
|
||||||
final int h = ZLTextSelectionCursor.getHeight();
|
|
||||||
final int a = ZLTextSelectionCursor.getAccent();
|
|
||||||
final int[] xs = { pt.X, pt.X + w, pt.X + w, pt.X - w, pt.X - w };
|
|
||||||
final int[] ys = { pt.Y - a, pt.Y, pt.Y + h, pt.Y + h, pt.Y };
|
|
||||||
context.setFillColor(context.getBackgroundColor(), 192);
|
|
||||||
context.fillPolygon(xs, ys);
|
|
||||||
context.setLineColor(getTextColor(ZLTextHyperlink.NO_LINK));
|
|
||||||
context.drawPolygonalLine(xs, ys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -501,34 +463,22 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
int x = getLeftMargin();
|
int x = getLeftMargin();
|
||||||
int y = getTopMargin();
|
int y = getTopMargin();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
int columnIndex = 0;
|
||||||
ZLTextLineInfo previousInfo = null;
|
ZLTextLineInfo previousInfo = null;
|
||||||
for (ZLTextLineInfo info : lineInfos) {
|
for (ZLTextLineInfo info : lineInfos) {
|
||||||
info.adjust(previousInfo);
|
info.adjust(previousInfo);
|
||||||
prepareTextLine(page, info, x, y);
|
prepareTextLine(page, info, x, y, columnIndex);
|
||||||
y += info.Height + info.Descent + info.VSpaceAfter;
|
y += info.Height + info.Descent + info.VSpaceAfter;
|
||||||
labels[++index] = page.TextElementMap.size();
|
labels[++index] = page.TextElementMap.size();
|
||||||
if (index == page.Column0Height) {
|
if (index == page.Column0Height) {
|
||||||
y = getTopMargin();
|
y = getTopMargin();
|
||||||
x += page.getTextWidth() + getSpaceBetweenColumns();
|
x += page.getTextWidth() + getSpaceBetweenColumns();
|
||||||
|
columnIndex = 1;
|
||||||
}
|
}
|
||||||
previousInfo = info;
|
previousInfo = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ZLTextHighlighting> hilites = findHilites(page);
|
final List<ZLTextHighlighting> hilites = findHilites(page);
|
||||||
if (!hilites.isEmpty()) {
|
|
||||||
x = getLeftMargin();
|
|
||||||
y = getTopMargin();
|
|
||||||
index = 0;
|
|
||||||
for (ZLTextLineInfo info : lineInfos) {
|
|
||||||
drawHighlightings(page, hilites, info, labels[index], labels[index + 1], x, y);
|
|
||||||
y += info.Height + info.Descent + info.VSpaceAfter;
|
|
||||||
++index;
|
|
||||||
if (index == page.Column0Height) {
|
|
||||||
y = getTopMargin();
|
|
||||||
x += page.getTextWidth() + getSpaceBetweenColumns();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x = getLeftMargin();
|
x = getLeftMargin();
|
||||||
y = getTopMargin();
|
y = getTopMargin();
|
||||||
|
@ -543,13 +493,34 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextRegion outlinedElementRegion = getOutlinedRegion(page);
|
for (ZLTextHighlighting h : hilites) {
|
||||||
if (outlinedElementRegion != null && myShowOutline) {
|
int mode = Hull.DrawMode.None;
|
||||||
outlinedElementRegion.draw(context);
|
|
||||||
|
final ZLColor bgColor = h.getBackgroundColor();
|
||||||
|
if (bgColor != null) {
|
||||||
|
context.setFillColor(bgColor, 128);
|
||||||
|
mode |= Hull.DrawMode.Fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSelectionCursor(context, getSelectionCursorPoint(page, ZLTextSelectionCursor.Left));
|
final ZLColor outlineColor = h.getOutlineColor();
|
||||||
drawSelectionCursor(context, getSelectionCursorPoint(page, ZLTextSelectionCursor.Right));
|
if (outlineColor != null) {
|
||||||
|
context.setLineColor(outlineColor);
|
||||||
|
mode |= Hull.DrawMode.Outline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != Hull.DrawMode.None) {
|
||||||
|
h.hull(page).draw(getContext(), mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ZLTextRegion outlinedElementRegion = getOutlinedRegion(page);
|
||||||
|
if (outlinedElementRegion != null && myShowOutline) {
|
||||||
|
context.setLineColor(getSelectionBackgroundColor());
|
||||||
|
outlinedElementRegion.hull().draw(context, Hull.DrawMode.Outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawSelectionCursor(context, page, SelectionCursor.Which.Left);
|
||||||
|
drawSelectionCursor(context, page, SelectionCursor.Which.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZLTextPage getPage(PageIndex pageIndex) {
|
private ZLTextPage getPage(PageIndex pageIndex) {
|
||||||
|
@ -847,45 +818,6 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
return hilites;
|
return hilites;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawHighlightings(ZLTextPage page, List<ZLTextHighlighting> hilites, ZLTextLineInfo info, int from, int to, int x, int y) {
|
|
||||||
if (from == to) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ZLTextElementArea fromArea = page.TextElementMap.get(from);
|
|
||||||
final ZLTextElementArea toArea = page.TextElementMap.get(to - 1);
|
|
||||||
for (ZLTextHighlighting h : hilites) {
|
|
||||||
final ZLColor bgColor = h.getBackgroundColor();
|
|
||||||
if (bgColor == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final ZLTextElementArea selectionStartArea = h.getStartArea(page);
|
|
||||||
if (selectionStartArea == null || selectionStartArea.compareTo(toArea) > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final ZLTextElementArea selectionEndArea = h.getEndArea(page);
|
|
||||||
if (selectionEndArea == null || selectionEndArea.compareTo(fromArea) < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int top = y + 1;
|
|
||||||
int left, right, bottom = y + info.Height + info.Descent;
|
|
||||||
if (selectionStartArea.compareTo(fromArea) < 0) {
|
|
||||||
left = x;
|
|
||||||
} else {
|
|
||||||
left = selectionStartArea.XStart;
|
|
||||||
}
|
|
||||||
if (selectionEndArea.compareTo(toArea) > 0) {
|
|
||||||
right = x + page.getTextWidth() - 1;
|
|
||||||
bottom += info.VSpaceAfter;
|
|
||||||
} else {
|
|
||||||
right = selectionEndArea.XEnd;
|
|
||||||
}
|
|
||||||
getContext().setFillColor(bgColor);
|
|
||||||
getContext().fillRectangle(left, top, right, bottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract ZLPaintContext.ColorAdjustingMode getAdjustingModeForImages();
|
protected abstract ZLPaintContext.ColorAdjustingMode getAdjustingModeForImages();
|
||||||
|
|
||||||
private static final char[] SPACE = new char[] { ' ' };
|
private static final char[] SPACE = new char[] { ' ' };
|
||||||
|
@ -895,9 +827,13 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
int index = from;
|
int index = from;
|
||||||
final int endElementIndex = info.EndElementIndex;
|
final int endElementIndex = info.EndElementIndex;
|
||||||
int charIndex = info.RealStartCharIndex;
|
int charIndex = info.RealStartCharIndex;
|
||||||
|
final List<ZLTextElementArea> pageAreas = page.TextElementMap.areas();
|
||||||
|
if (to > pageAreas.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (int wordIndex = info.RealStartElementIndex; wordIndex != endElementIndex && index < to; ++wordIndex, charIndex = 0) {
|
for (int wordIndex = info.RealStartElementIndex; wordIndex != endElementIndex && index < to; ++wordIndex, charIndex = 0) {
|
||||||
final ZLTextElement element = paragraph.getElement(wordIndex);
|
final ZLTextElement element = paragraph.getElement(wordIndex);
|
||||||
final ZLTextElementArea area = page.TextElementMap.get(index);
|
final ZLTextElementArea area = pageAreas.get(index);
|
||||||
if (element == area.Element) {
|
if (element == area.Element) {
|
||||||
++index;
|
++index;
|
||||||
if (area.ChangeStyle) {
|
if (area.ChangeStyle) {
|
||||||
|
@ -961,7 +897,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index != to) {
|
if (index != to) {
|
||||||
ZLTextElementArea area = page.TextElementMap.get(index++);
|
ZLTextElementArea area = pageAreas.get(index++);
|
||||||
if (area.ChangeStyle) {
|
if (area.ChangeStyle) {
|
||||||
setTextStyle(area.Style);
|
setTextStyle(area.Style);
|
||||||
}
|
}
|
||||||
|
@ -1306,7 +1242,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareTextLine(ZLTextPage page, ZLTextLineInfo info, int x, int y) {
|
private void prepareTextLine(ZLTextPage page, ZLTextLineInfo info, int x, int y, int columnIndex) {
|
||||||
y = Math.min(y + info.Height, getTopMargin() + page.getTextHeight() - 1);
|
y = Math.min(y + info.Height, getTopMargin() + page.getTextHeight() - 1);
|
||||||
|
|
||||||
final ZLPaintContext context = getContext();
|
final ZLPaintContext context = getContext();
|
||||||
|
@ -1357,7 +1293,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
true, // is last in element
|
true, // is last in element
|
||||||
false, // add hyphenation sign
|
false, // add hyphenation sign
|
||||||
false, // changed style
|
false, // changed style
|
||||||
getTextStyle(), element, x, x + spaceLength, y, y
|
getTextStyle(), element, x, x + spaceLength, y, y, columnIndex
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
spaceElement = null;
|
spaceElement = null;
|
||||||
|
@ -1381,7 +1317,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
true, // is last in element
|
true, // is last in element
|
||||||
false, // add hyphenation sign
|
false, // add hyphenation sign
|
||||||
changeStyle, getTextStyle(), element,
|
changeStyle, getTextStyle(), element,
|
||||||
x, x + width - 1, y - height + 1, y + descent
|
x, x + width - 1, y - height + 1, y + descent, columnIndex
|
||||||
));
|
));
|
||||||
changeStyle = false;
|
changeStyle = false;
|
||||||
wordOccurred = true;
|
wordOccurred = true;
|
||||||
|
@ -1407,7 +1343,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
false, // is last in element
|
false, // is last in element
|
||||||
addHyphenationSign,
|
addHyphenationSign,
|
||||||
changeStyle, getTextStyle(), word,
|
changeStyle, getTextStyle(), word,
|
||||||
x, x + width - 1, y - height + 1, y + descent
|
x, x + width - 1, y - height + 1, y + descent, columnIndex
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1773,6 +1709,10 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
return myCurrentPage.TextElementMap.findRegion(x, y, maxDistance, filter);
|
return myCurrentPage.TextElementMap.findRegion(x, y, maxDistance, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ZLTextElementAreaVector.RegionPair findRegionsPair(int x, int y, ZLTextRegion.Filter filter) {
|
||||||
|
return myCurrentPage.TextElementMap.findRegionsPair(x, y, getColumnIndex(x), filter);
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean initSelection(int x, int y) {
|
protected boolean initSelection(int x, int y) {
|
||||||
y -= getTextStyleCollection().getBaseStyle().getFontSize() / 2;
|
y -= getTextStyleCollection().getBaseStyle().getFontSize() / 2;
|
||||||
if (!mySelection.start(x, y)) {
|
if (!mySelection.start(x, y)) {
|
||||||
|
@ -1790,8 +1730,8 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZLTextRegion.Soul getSelectionSoul() {
|
public ZLTextHighlighting getSelectionHighlighting() {
|
||||||
return mySelection.getSoul();
|
return mySelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectionStartY() {
|
public int getSelectionStartY() {
|
||||||
|
|
|
@ -110,6 +110,13 @@ abstract class ZLTextViewBase extends ZLView {
|
||||||
return getContextHeight() - getTopMargin() - getBottomMargin();
|
return getContextHeight() - getTopMargin() - getBottomMargin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected int getColumnIndex(int x) {
|
||||||
|
if (!twoColumnView()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 2 * x <= getContextWidth() + getLeftMargin() - getRightMargin() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
public int getTextColumnWidth() {
|
public int getTextColumnWidth() {
|
||||||
return twoColumnView()
|
return twoColumnView()
|
||||||
? (getContextWidth() - getLeftMargin() - getSpaceBetweenColumns() - getRightMargin()) / 2
|
? (getContextWidth() - getLeftMargin() - getSpaceBetweenColumns() - getRightMargin()) / 2
|
||||||
|
|
|
@ -103,6 +103,10 @@ public final class ZLTextWord extends ZLTextElement {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
return getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
return new String(Data, Offset, Length);
|
return new String(Data, Offset, Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue