1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-06 03:50:19 +02:00

Merge branch '1.2' into tts

This commit is contained in:
Nikolay Pultsin 2011-06-13 10:16:18 +01:00
commit 148c442f39
49 changed files with 512 additions and 298 deletions

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.geometerplus.zlibrary.ui.android" android:versionCode="10014" android:versionName="1.0.12" android:installLocation="auto">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.geometerplus.zlibrary.ui.android" android:versionCode="10200" android:versionName="1.2.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="4" />
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
<uses-permission android:name="android.permission.INTERNET" />

View file

@ -1,5 +1,7 @@
===== 1.1.0 (Jun ??, 2011) =====
* Text selection
===== 1.2.0 (??? ??, 2011) =====
===== 1.1.0 (Jun 11, 2011) =====
* Text selection (original code by Dmitry Gordeev)
* Localization to Traditional Chinese (by Fung.T)
===== 1.0.12 (May 13, 2011) =====

View file

@ -1 +1 @@
1.1.0
1.2.0

View file

@ -542,6 +542,7 @@
<node name="dictionary" value="Slovník">
<node name="summary" value="Nastavení slovníku"/>
<node name="dictionary" value="Slovník"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Dlouhé klepnutí">
<node name="doNothing" value="Dlouhé klepnutí nedělá nic"/>
<node name="selectSingleWord" value="Dlouhé klepnutí vybere slovo"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Dictionary" toBeTranslated="true">
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
<node name="dictionary" value="Dictionary" toBeTranslated="true"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>

View file

@ -543,6 +543,7 @@
<node name="dictionary" value="Dictionary">
<node name="summary" value="Dictionary settings"/>
<node name="dictionary" value="Dictionary"/>
<node name="translator" value="Translator"/>
<node name="tappingAction" value="Long tapping action">
<node name="doNothing" value="Long tapping does nothing"/>
<node name="selectSingleWord" value="Long tapping selects single word"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Dictionnaire">
<node name="summary" value="Paramètres du dictionnaire"/>
<node name="dictionary" value="Dictionnaire"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Configuration de l'appui long">
<node name="doNothing" value="Un appui long ne fait rien"/>
<node name="selectSingleWord" value="Un appui long selectionne le mot"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Dicionario">
<node name="summary" value="Preferencias do dicionario"/>
<node name="dictionary" value="Dicionario"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Acción de pulsación longa">
<node name="doNothing" value="Pulsación longa non fai nada"/>
<node name="selectSingleWord" value="Pulsación longa selecciona a palabra"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Szótár">
<node name="summary" value="Szótár beállításai"/>
<node name="dictionary" value="Szótár"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Hosszú érintés">
<node name="doNothing" value="Nem történik semmi hosszú érintésre"/>
<node name="selectSingleWord" value="A hosszú érintés kijelöli a szót"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Dictionary" toBeTranslated="true">
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
<node name="dictionary" value="Dictionary" toBeTranslated="true"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Woordenboek">
<node name="summary" value="Woordenboek instellingen"/>
<node name="dictionary" value="Woordenboek"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Словарь">
<node name="summary" value="Настройки словаря"/>
<node name="dictionary" value="Словарь"/>
<node name="translator" value="Переводчик"/>
<node name="tappingAction" value="Действие при долгом нажатии на экран">
<node name="doNothing" value="Ничего не делать"/>
<node name="selectSingleWord" value="Выделять одно слово"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="พจนานุกรม">
<node name="summary" value="การตั้งค่าพจนานุกรม"/>
<node name="dictionary" value="พจนานุกรม"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="การทำงานเมื่อกดค้างที่หน้าจอ">
<node name="doNothing" value="ไม่มีอะไรเกิดขึ้น"/>
<node name="selectSingleWord" value="เลือกคำเมื่อกดค้างที่หน้าจอ"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Dictionary" toBeTranslated="true">
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
<node name="dictionary" value="Dictionary" toBeTranslated="true"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="Từ điển">
<node name="summary" value="Cài đặt từ điển"/>
<node name="dictionary" value="Từ điển"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="Nhấn giữ">
<node name="doNothing" value="Không làm gì khi nhấn giữ"/>
<node name="selectSingleWord" value="Chọn từ khi nhấn giữ"/>

View file

@ -528,6 +528,7 @@
<node name="dictionary" value="字典">
<node name="summary" value="字典设定"/>
<node name="dictionary" value="字典"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="长拍触行为动作">
<node name="doNothing" value="长拍触不做任何动作"/>
<node name="selectSingleWord" value="长拍触选择词语"/>

View file

@ -547,6 +547,7 @@
<node name="dictionary" value="字典">
<node name="summary" value="字典設定"/>
<node name="dictionary" value="字典"/>
<node name="translator" value="Translator" toBeTranslated="true"/>
<node name="tappingAction" value="長按動作">
<node name="doNothing" value="長按不做任何動作"/>
<node name="selectSingleWord" value="長按選字"/>

View file

@ -10,4 +10,4 @@
# Project target.
target=android-8
java.encoding=utf-8
#proguard.config=proguard.cfg
proguard.config=proguard.cfg

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/selection_dictionary_active" />
<item android:drawable="@drawable/selection_dictionary_default" />
<item android:state_pressed="true" android:drawable="@drawable/selection_translate_active" />
<item android:drawable="@drawable/selection_translate_default" />
</selector>

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

@ -45,7 +45,8 @@ public abstract class DictionaryUtil {
// Map: dictionary info -> hide if package is not installed
private static LinkedHashMap<PackageInfo,Boolean> ourDictionaryInfos =
new LinkedHashMap<PackageInfo,Boolean>();
private static ZLStringOption ourDictionaryOption;
private static ZLStringOption ourSingleWordTranslatorOption;
private static ZLStringOption ourMultiWordTranslatorOption;
private static class InfoReader extends ZLXMLReaderAdapter {
@Override
@ -113,15 +114,24 @@ public abstract class DictionaryUtil {
throw new RuntimeException("There are no available dictionary infos");
}
public static ZLStringOption dictionaryOption() {
if (ourDictionaryOption == null) {
ourDictionaryOption = new ZLStringOption("Dictionary", "Id", firstInfo().Id);
public static ZLStringOption singleWordTranslatorOption() {
if (ourSingleWordTranslatorOption == null) {
ourSingleWordTranslatorOption = new ZLStringOption("Dictionary", "Id", firstInfo().Id);
}
return ourDictionaryOption;
return ourSingleWordTranslatorOption;
}
private static PackageInfo getCurrentDictionaryInfo() {
final String id = dictionaryOption().getValue();
public static ZLStringOption multiWordTranslatorOption() {
if (ourMultiWordTranslatorOption == null) {
ourMultiWordTranslatorOption = new ZLStringOption("Translator", "Id", firstInfo().Id);
}
return ourMultiWordTranslatorOption;
}
private static PackageInfo getCurrentDictionaryInfo(boolean singleWord) {
final ZLStringOption option = singleWord
? singleWordTranslatorOption() : multiWordTranslatorOption();
final String id = option.getValue();
for (PackageInfo info : infos().keySet()) {
if (info.Id.equals(id)) {
return info;
@ -130,8 +140,8 @@ public abstract class DictionaryUtil {
return firstInfo();
}
private static Intent getDictionaryIntent(String text) {
return getDictionaryIntent(getCurrentDictionaryInfo(), text);
private static Intent getDictionaryIntent(String text, boolean singleWord) {
return getDictionaryIntent(getCurrentDictionaryInfo(singleWord), text);
}
public static Intent getDictionaryIntent(PackageInfo dictionaryInfo, String text) {
@ -154,8 +164,19 @@ public abstract class DictionaryUtil {
}
}
public static void openTextInDictionary(Activity activity, String text, int selectionTop, int selectionBottom) {
final PackageInfo info = getCurrentDictionaryInfo();
public static void openTextInDictionary(Activity activity, String text, boolean singleWord, int selectionTop, int selectionBottom) {
if (singleWord) {
int start = 0;
int end = text.length();
for (; start < end && !Character.isLetterOrDigit(text.charAt(start)); ++start);
for (; start < end && !Character.isLetterOrDigit(text.charAt(end - 1)); --end);
if (start == end) {
return;
}
text = text.substring(start, end);
}
final PackageInfo info = getCurrentDictionaryInfo(singleWord);
final Intent intent = getDictionaryIntent(info, text);
try {
if ("ColorDict".equals(info.Id)) {
@ -175,30 +196,21 @@ public abstract class DictionaryUtil {
}
activity.startActivity(intent);
} catch (ActivityNotFoundException e) {
DictionaryUtil.installDictionaryIfNotInstalled(activity);
DictionaryUtil.installDictionaryIfNotInstalled(activity, singleWord);
}
}
public static void openWordInDictionary(Activity activity, ZLTextWord word, ZLTextRegion region) {
final String text = word.toString();
int start = 0;
int end = text.length();
for (; start < end && !Character.isLetterOrDigit(text.charAt(start)); ++start);
for (; start < end && !Character.isLetterOrDigit(text.charAt(end - 1)); --end);
if (start == end) {
return;
}
openTextInDictionary(
activity, text.substring(start, end), region.getTop(), region.getBottom()
activity, word.toString(), true, region.getTop(), region.getBottom()
);
}
public static void installDictionaryIfNotInstalled(final Activity activity) {
if (PackageUtil.canBeStarted(activity, getDictionaryIntent("test"), false)) {
public static void installDictionaryIfNotInstalled(final Activity activity, boolean singleWord) {
if (PackageUtil.canBeStarted(activity, getDictionaryIntent("test", singleWord), false)) {
return;
}
final PackageInfo dictionaryInfo = getCurrentDictionaryInfo();
final PackageInfo dictionaryInfo = getCurrentDictionaryInfo(singleWord);
final ZLResource dialogResource = ZLResource.resource("dialog");
final ZLResource buttonResource = dialogResource.getResource("button");

View file

@ -101,8 +101,8 @@ public final class FBReader extends ZLAndroidActivity {
fbReader.addAction(ActionCode.SELECTION_HIDE_PANEL, new SelectionHidePanelAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_COPY_TO_CLIPBOARD, new SelectionCopyAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_SHARE, new SelectionShareAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_OPEN_IN_DICTIONARY, new SelectionDictionaryAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_ADD_BOOKMARK, new SelectionBookmarkAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_TRANSLATE, new SelectionTranslateAction(this, fbReader));
fbReader.addAction(ActionCode.SELECTION_BOOKMARK, new SelectionBookmarkAction(this, fbReader));
fbReader.addAction(ActionCode.PROCESS_HYPERLINK, new ProcessHyperlinkAction(this, fbReader));

View file

@ -48,8 +48,8 @@ class SelectionPopup extends ButtonsPopupPanel {
addButton(ActionCode.SELECTION_COPY_TO_CLIPBOARD, true, R.drawable.selection_copy);
addButton(ActionCode.SELECTION_SHARE, true, R.drawable.selection_share);
addButton(ActionCode.SELECTION_OPEN_IN_DICTIONARY, true, R.drawable.selection_dictionary);
addButton(ActionCode.SELECTION_ADD_BOOKMARK, true, R.drawable.selection_bookmark);
addButton(ActionCode.SELECTION_TRANSLATE, true, R.drawable.selection_translate);
addButton(ActionCode.SELECTION_BOOKMARK, true, R.drawable.selection_bookmark);
addButton(ActionCode.SELECTION_CLEAR, true, R.drawable.selection_close);
}
@ -69,10 +69,10 @@ class SelectionPopup extends ButtonsPopupPanel {
final int diffTop = screenHeight - selectionEndY;
final int diffBottom = selectionStartY;
if (diffTop > diffBottom) {
verticalPosition = diffTop > myWindow.getHeight() + 10
verticalPosition = diffTop > myWindow.getHeight() + 20
? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.CENTER_VERTICAL;
} else {
verticalPosition = diffBottom > myWindow.getHeight() + 10
verticalPosition = diffBottom > myWindow.getHeight() + 20
? RelativeLayout.ALIGN_PARENT_TOP : RelativeLayout.CENTER_VERTICAL;
}

View file

@ -22,17 +22,20 @@ package org.geometerplus.android.fbreader;
import org.geometerplus.fbreader.fbreader.FBReaderApp;
import org.geometerplus.fbreader.fbreader.FBView;
public class SelectionDictionaryAction extends FBAndroidAction {
SelectionDictionaryAction(FBReader baseActivity, FBReaderApp fbreader) {
public class SelectionTranslateAction extends FBAndroidAction {
SelectionTranslateAction(FBReader baseActivity, FBReaderApp fbreader) {
super(baseActivity, fbreader);
}
public void run() {
final FBView fbview = Reader.getTextView();
final int selectionStartY = fbview.getSelectionStartY(), selectionEndY = fbview.getSelectionEndY();
final String text = fbview.getSelectedText();
Reader.getTextView().clearSelection();
DictionaryUtil.openTextInDictionary(BaseActivity, text, selectionStartY, selectionEndY);
DictionaryUtil.openTextInDictionary(
BaseActivity,
fbview.getSelectedText(),
fbview.getCountOfSelectedWords() == 1,
fbview.getSelectionStartY(),
fbview.getSelectionEndY()
);
fbview.clearSelection();
}
}

View file

@ -32,10 +32,10 @@ import org.geometerplus.android.fbreader.PackageInfo;
class DictionaryPreference extends ZLStringListPreference {
private final ZLStringOption myOption;
DictionaryPreference(Context context, ZLResource resource, String resourceKey) {
DictionaryPreference(Context context, ZLResource resource, String resourceKey, ZLStringOption dictionaryOption) {
super(context, resource, resourceKey);
myOption = DictionaryUtil.dictionaryOption();
myOption = dictionaryOption;
final List<PackageInfo> infos = DictionaryUtil.dictionaryInfos(context);
final String[] values = new String[infos.size()];

View file

@ -34,6 +34,8 @@ import org.geometerplus.fbreader.fbreader.*;
import org.geometerplus.fbreader.Paths;
import org.geometerplus.fbreader.bookmodel.FBTextKind;
import org.geometerplus.android.fbreader.DictionaryUtil;
public class PreferenceActivity extends ZLPreferenceActivity {
public PreferenceActivity() {
super("Preferences");
@ -375,7 +377,14 @@ public class PreferenceActivity extends ZLPreferenceActivity {
dictionaryScreen.addPreference(new DictionaryPreference(
this,
dictionaryScreen.Resource,
"dictionary"
"dictionary",
DictionaryUtil.singleWordTranslatorOption()
));
dictionaryScreen.addPreference(new DictionaryPreference(
this,
dictionaryScreen.Resource,
"translator",
DictionaryUtil.multiWordTranslatorOption()
));
dictionaryScreen.addPreference(new ZLBooleanPreference(
this,

View file

@ -63,6 +63,6 @@ public interface ActionCode {
String SELECTION_CLEAR = "selectionClear";
String SELECTION_COPY_TO_CLIPBOARD = "selectionCopyToClipboard";
String SELECTION_SHARE = "selectionShare";
String SELECTION_OPEN_IN_DICTIONARY = "selectionOpenInDictionary";
String SELECTION_ADD_BOOKMARK = "selectionAddBookmark";
String SELECTION_TRANSLATE = "selectionTranslate";
String SELECTION_BOOKMARK = "selectionBookmark";
}

View file

@ -195,7 +195,7 @@ public final class FBView extends ZLTextView {
}
if (isFlickScrollingEnabled()) {
myReader.getViewWidget().startAutoScrolling(
myReader.getViewWidget().startAnimatedScrolling(
x, y, ScrollingPreferences.Instance().AnimationSpeedOption.getValue()
);
return true;
@ -601,17 +601,27 @@ public final class FBView extends ZLTextView {
@Override
protected void releaseSelectionCursor() {
super.releaseSelectionCursor();
myReader.doAction(ActionCode.SELECTION_SHOW_PANEL);
if (getCountOfSelectedWords() > 0) {
myReader.doAction(ActionCode.SELECTION_SHOW_PANEL);
}
}
public String getSelectedText() {
final TextBuilderTraverser traverser = new TextBuilderTraverser(this);
final TextBuildTraverser traverser = new TextBuildTraverser(this);
if (!isSelectionEmpty()) {
traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition());
}
return traverser.getText();
}
public int getCountOfSelectedWords() {
final WordCountTraverser traverser = new WordCountTraverser(this);
if (!isSelectionEmpty()) {
traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition());
}
return traverser.getCount();
}
public static final int SCROLLBAR_SHOW_AS_FOOTER = 3;
@Override

View file

@ -21,10 +21,10 @@ package org.geometerplus.fbreader.fbreader;
import org.geometerplus.zlibrary.text.view.*;
class TextBuilderTraverser extends ZLTextTraverser {
class TextBuildTraverser extends ZLTextTraverser {
protected final StringBuilder myBuffer = new StringBuilder();
TextBuilderTraverser(ZLTextView view) {
TextBuildTraverser(ZLTextView view) {
super(view);
}

View file

@ -39,7 +39,7 @@ class TurnPageAction extends FBAction {
public void run() {
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
Reader.getViewWidget().startAutoScrolling(
Reader.getViewWidget().startAnimatedScrolling(
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
preferences.HorizontalOption.getValue()
? FBView.Direction.rightToLeft : FBView.Direction.up,
@ -49,7 +49,7 @@ class TurnPageAction extends FBAction {
public void runWithCoordinates(int x, int y) {
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
Reader.getViewWidget().startAutoScrolling(
Reader.getViewWidget().startAnimatedScrolling(
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
x, y,
preferences.HorizontalOption.getValue()

View file

@ -39,7 +39,7 @@ class VolumeKeyTurnPageAction extends FBAction {
forward = !forward;
}
Reader.getViewWidget().startAutoScrolling(
Reader.getViewWidget().startAnimatedScrolling(
forward ? FBView.PageIndex.next : FBView.PageIndex.previous,
preferences.HorizontalOption.getValue()
? FBView.Direction.rightToLeft : FBView.Direction.up,

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2007-2011 Geometer Plus <contact@geometerplus.com>
*
* 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.text.view.*;
class WordCountTraverser extends ZLTextTraverser {
protected int myCount;
WordCountTraverser(ZLTextView view) {
super(view);
}
@Override
protected void processWord(ZLTextWord word) {
++myCount;
}
@Override
protected void processControlElement(ZLTextControlElement control) {
// does nothing
}
@Override
protected void processSpace() {
// does nothing
}
@Override
protected void processEndOfParagraph() {
// does nothing
}
public int getCount() {
return myCount;
}
}

View file

@ -25,7 +25,7 @@ public interface ZLViewWidget {
void startManualScrolling(int x, int y, ZLView.Direction direction);
void scrollManuallyTo(int x, int y);
void startAutoScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed);
void startAutoScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed);
void startAutoScrolling(int x, int y, int speed);
void startAnimatedScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed);
void startAnimatedScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed);
void startAnimatedScrolling(int x, int y, int speed);
}

View file

@ -31,7 +31,9 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
final ZLTextStyle Style;
final ZLTextElement Element;
ZLTextElementArea(int paragraphIndex, int elementIndex, int charIndex, int length, boolean addHyphenationSign, boolean changeStyle, ZLTextStyle style, ZLTextElement element, int xStart, int xEnd, int yStart, int yEnd) {
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) {
super(paragraphIndex, elementIndex, charIndex);
XStart = xStart;
@ -40,6 +42,8 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
YEnd = yEnd;
Length = length;
myIsLastInElement = lastInElement;
AddHyphenationSign = addHyphenationSign;
ChangeStyle = changeStyle;
Style = style;
@ -55,7 +59,6 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
}
boolean isLastInElement() {
// TODO: support multi-part (> 2 part) words
return !(Element instanceof ZLTextWord) || CharIndex > 0;
return myIsLastInElement;
}
}

View file

@ -21,20 +21,31 @@ package org.geometerplus.zlibrary.text.view;
import java.util.*;
final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
private static final long serialVersionUID = -7880472347947563506L;
private final ArrayList<ZLTextRegion> myElementRegions = new ArrayList<ZLTextRegion>();
final class ZLTextElementAreaVector {
private final List<ZLTextElementArea> myAreas =
Collections.synchronizedList(new ArrayList<ZLTextElementArea>());
private final List<ZLTextRegion> myElementRegions =
Collections.synchronizedList(new ArrayList<ZLTextRegion>());
private ZLTextRegion myCurrentElementRegion;
@Override
public void clear() {
myElementRegions.clear();
myCurrentElementRegion = null;
super.clear();
myAreas.clear();
}
public boolean isEmpty() {
return myAreas.isEmpty();
}
public int size() {
return myAreas.size();
}
public ZLTextElementArea get(int index) {
return myAreas.get(index);
}
@Override
public boolean add(ZLTextElementArea area) {
if (myCurrentElementRegion != null
&& myCurrentElementRegion.getSoul().accepts(area)) {
@ -50,13 +61,13 @@ final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
soul = new ZLTextWordRegionSoul(area, (ZLTextWord)area.Element);
}
if (soul != null) {
myCurrentElementRegion = new ZLTextRegion(soul, this, size());
myCurrentElementRegion = new ZLTextRegion(soul, myAreas, size());
myElementRegions.add(myCurrentElementRegion);
} else {
myCurrentElementRegion = null;
}
}
return super.add(area);
return myAreas.add(area);
}
ZLTextElementArea binarySearch(int x, int y) {
@ -80,17 +91,121 @@ final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
return null;
}
List<ZLTextRegion> elementRegions() {
return Collections.unmodifiableList(myElementRegions);
}
ZLTextRegion getRegion(ZLTextRegion.Soul soul) {
if (soul == null) {
return null;
}
for (ZLTextRegion region : myElementRegions) {
if (soul.equals(region.getSoul())) {
return region;
synchronized (myElementRegions) {
for (ZLTextRegion region : myElementRegions) {
if (soul.equals(region.getSoul())) {
return region;
}
}
}
return null;
}
ZLTextRegion findRegion(int x, int y, int maxDistance, ZLTextRegion.Filter filter) {
ZLTextRegion bestRegion = null;
int distance = maxDistance + 1;
synchronized (myElementRegions) {
for (ZLTextRegion region : myElementRegions) {
if (filter.accepts(region)) {
final int d = region.distanceTo(x, y);
if (d < distance) {
bestRegion = region;
distance = d;
}
}
}
}
return bestRegion;
}
protected ZLTextRegion nextRegion(ZLTextRegion currentRegion, ZLTextView.Direction direction, ZLTextRegion.Filter filter) {
synchronized (myElementRegions) {
if (myElementRegions.isEmpty()) {
return null;
}
int index = currentRegion != null ? myElementRegions.indexOf(currentRegion) : -1;
switch (direction) {
case rightToLeft:
case up:
if (index == -1) {
index = myElementRegions.size() - 1;
} else if (index == 0) {
return null;
} else {
--index;
}
break;
case leftToRight:
case down:
if (index == myElementRegions.size() - 1) {
return null;
} else {
++index;
}
break;
}
switch (direction) {
case rightToLeft:
for (; index >= 0; --index) {
final ZLTextRegion candidate = myElementRegions.get(index);
if (filter.accepts(candidate) && candidate.isAtLeftOf(currentRegion)) {
return candidate;
}
}
break;
case leftToRight:
for (; index < myElementRegions.size(); ++index) {
final ZLTextRegion candidate = myElementRegions.get(index);
if (filter.accepts(candidate) && candidate.isAtRightOf(currentRegion)) {
return candidate;
}
}
break;
case down:
{
ZLTextRegion firstCandidate = null;
for (; index < myElementRegions.size(); ++index) {
final ZLTextRegion candidate = myElementRegions.get(index);
if (!filter.accepts(candidate)) {
continue;
}
if (candidate.isExactlyUnder(currentRegion)) {
return candidate;
}
if (firstCandidate == null && candidate.isUnder(currentRegion)) {
firstCandidate = candidate;
}
}
if (firstCandidate != null) {
return firstCandidate;
}
break;
}
case up:
ZLTextRegion firstCandidate = null;
for (; index >= 0; --index) {
final ZLTextRegion candidate = myElementRegions.get(index);
if (!filter.accepts(candidate)) {
continue;
}
if (candidate.isExactlyOver(currentRegion)) {
return candidate;
}
if (firstCandidate == null && candidate.isOver(currentRegion)) {
firstCandidate = candidate;
}
}
if (firstCandidate != null) {
return firstCandidate;
}
break;
}
}
return null;

View file

@ -26,7 +26,7 @@ import org.geometerplus.zlibrary.core.view.ZLPaintContext;
class ZLTextHorizontalConvexHull {
private final LinkedList<Rectangle> myRectangles = new LinkedList<Rectangle>();
ZLTextHorizontalConvexHull(List<ZLTextElementArea> textAreas) {
ZLTextHorizontalConvexHull(ZLTextElementArea[] textAreas) {
for (ZLTextElementArea area : textAreas) {
addArea(area);
}

View file

@ -19,14 +19,31 @@
package org.geometerplus.zlibrary.text.view;
import java.util.*;
public class ZLTextHyperlink {
public final byte Type;
public final String Id;
private List<Integer> myElementIndexes;
public static final ZLTextHyperlink NO_LINK = new ZLTextHyperlink((byte)0, null);
ZLTextHyperlink(byte type, String id) {
Type = type;
Id = id;
}
void addElementIndex(int elementIndex) {
if (myElementIndexes == null) {
myElementIndexes = new LinkedList<Integer>();
}
myElementIndexes.add(elementIndex);
}
List<Integer> elementIndexes() {
return myElementIndexes != null
? Collections.unmodifiableList(myElementIndexes)
: Collections.<Integer>emptyList();
}
}

View file

@ -19,12 +19,27 @@
package org.geometerplus.zlibrary.text.view;
import java.util.List;
public class ZLTextHyperlinkRegionSoul extends ZLTextRegion.Soul {
public final ZLTextHyperlink Hyperlink;
private static int startElementIndex(ZLTextHyperlink hyperlink, int fallback) {
final List<Integer> indexes = hyperlink.elementIndexes();
return indexes.isEmpty() ? fallback : indexes.get(0);
}
private static int endElementIndex(ZLTextHyperlink hyperlink, int fallback) {
final List<Integer> indexes = hyperlink.elementIndexes();
return indexes.isEmpty() ? fallback : indexes.get(indexes.size() - 1);
}
ZLTextHyperlinkRegionSoul(ZLTextPosition position, ZLTextHyperlink hyperlink) {
// TODO: fix this call
super(position.getParagraphIndex(), position.getElementIndex(), position.getElementIndex());
super(
position.getParagraphIndex(),
startElementIndex(hyperlink, position.getElementIndex()),
endElementIndex(hyperlink, position.getElementIndex())
);
Hyperlink = hyperlink;
}
}

View file

@ -34,7 +34,7 @@ public final class ZLTextParagraphCursor {
private int myFirstMark;
private int myLastMark;
private final List<ZLTextMark> myMarks;
private Processor(ZLTextParagraph paragraph, LineBreaker lineBreaker, List<ZLTextMark> marks, int paragraphIndex, ArrayList<ZLTextElement> elements) {
myParagraph = paragraph;
myLineBreaker = lineBreaker;
@ -54,20 +54,33 @@ public final class ZLTextParagraphCursor {
}
void fill() {
int hyperlinkDepth = 0;
ZLTextHyperlink hyperlink = null;
final ArrayList<ZLTextElement> elements = myElements;
for (ZLTextParagraph.EntryIterator it = myParagraph.iterator(); it.hasNext(); ) {
it.next();
switch (it.getType()) {
case ZLTextParagraph.Entry.TEXT:
processTextEntry(it.getTextData(), it.getTextOffset(), it.getTextLength());
processTextEntry(it.getTextData(), it.getTextOffset(), it.getTextLength(), hyperlink);
break;
case ZLTextParagraph.Entry.CONTROL:
if (hyperlink != null) {
hyperlinkDepth += it.getControlIsStart() ? 1 : -1;
if (hyperlinkDepth == 0) {
hyperlink = null;
}
}
if (it.getControlIsStart()) {
final byte hyperlinkType = it.getHyperlinkType();
if (hyperlinkType != 0) {
elements.add(new ZLTextHyperlinkControlElement(
it.getControlKind(), hyperlinkType, it.getHyperlinkId()
));
final ZLTextHyperlinkControlElement control =
new ZLTextHyperlinkControlElement(
it.getControlKind(), hyperlinkType, it.getHyperlinkId()
);
elements.add(control);
hyperlink = control.Hyperlink;
hyperlinkDepth = 1;
break;
}
}
@ -79,6 +92,9 @@ public final class ZLTextParagraphCursor {
if (image != null) {
ZLImageData data = ZLImageManager.Instance().getImageData(image);
if (data != null) {
if (hyperlink != null) {
hyperlink.addElementIndex(elements.size());
}
elements.add(new ZLTextImageElement(imageEntry.Id, data, image.getURI()));
}
}
@ -92,12 +108,12 @@ public final class ZLTextParagraphCursor {
}
}
}
private static byte[] ourBreaks = new byte[1024];
private static final int NO_SPACE = 0;
private static final int SPACE = 1;
//private static final int NON_BREAKABLE_SPACE = 2;
private void processTextEntry(final char[] data, final int offset, final int length) {
private void processTextEntry(final char[] data, final int offset, final int length, ZLTextHyperlink hyperlink) {
if (length != 0) {
if (ourBreaks.length < length) {
ourBreaks = new byte[length];
@ -116,7 +132,7 @@ public final class ZLTextParagraphCursor {
ch = data[offset + index];
if (Character.isSpace(ch)) {
if (index > 0 && spaceState == NO_SPACE) {
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart);
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart, hyperlink);
}
spaceState = SPACE;
} else {
@ -134,7 +150,7 @@ public final class ZLTextParagraphCursor {
breaks[index - 1] != LineBreaker.NOBREAK &&
previousChar != '-' &&
index != wordStart) {
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart);
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart, hyperlink);
wordStart = index;
}
break;
@ -149,14 +165,14 @@ public final class ZLTextParagraphCursor {
//case NON_BREAKABLE_SPACE:
//break;
case NO_SPACE:
addWord(data, offset + wordStart, length - wordStart, myOffset + wordStart);
addWord(data, offset + wordStart, length - wordStart, myOffset + wordStart, hyperlink);
break;
}
myOffset += length;
}
}
private final void addWord(char[] data, int offset, int len, int paragraphOffset) {
private final void addWord(char[] data, int offset, int len, int paragraphOffset, ZLTextHyperlink hyperlink) {
ZLTextWord word = new ZLTextWord(data, offset, len, paragraphOffset);
for (int i = myFirstMark; i < myLastMark; ++i) {
final ZLTextMark mark = (ZLTextMark)myMarks.get(i);
@ -164,10 +180,13 @@ public final class ZLTextParagraphCursor {
word.addMark(mark.Offset - paragraphOffset, mark.Length);
}
}
myElements.add(word);
if (hyperlink != null) {
hyperlink.addElementIndex(myElements.size());
}
myElements.add(word);
}
}
public final int Index;
public final ZLTextModel Model;
private final ArrayList<ZLTextElement> myElements = new ArrayList<ZLTextElement>();
@ -177,7 +196,7 @@ public final class ZLTextParagraphCursor {
Index = Math.min(index, Model.getParagraphsNumber() - 1);
fill();
}
static ZLTextParagraphCursor cursor(ZLTextModel model, int index) {
ZLTextParagraphCursor result = ZLTextParagraphCursorCache.get(model, index);
if (result == null) {
@ -201,7 +220,7 @@ public final class ZLTextParagraphCursor {
break;
}
}
void clear() {
myElements.clear();
}
@ -213,11 +232,11 @@ public final class ZLTextParagraphCursor {
public boolean isLast() {
return (Index + 1 >= Model.getParagraphsNumber());
}
public boolean isEndOfSection() {
return (Model.getParagraph(Index).getKind() == ZLTextParagraph.Kind.END_OF_SECTION_PARAGRAPH);
return (Model.getParagraph(Index).getKind() == ZLTextParagraph.Kind.END_OF_SECTION_PARAGRAPH);
}
int getParagraphLength() {
return myElements.size();
}
@ -229,7 +248,7 @@ public final class ZLTextParagraphCursor {
public ZLTextParagraphCursor next() {
return isLast() ? null : cursor(Model, Index + 1);
}
ZLTextElement getElement(int index) {
try {
return myElements.get(index);
@ -239,7 +258,7 @@ public final class ZLTextParagraphCursor {
}
ZLTextParagraph getParagraph() {
return Model.getParagraph(Index);
return Model.getParagraph(Index);
}
@Override

View file

@ -23,7 +23,7 @@ import java.util.*;
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
public final class ZLTextRegion {
public static abstract class Soul implements Comparable<Soul> {
final int ParagraphIndex;
final int StartElementIndex;
@ -107,14 +107,16 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
};
private final Soul mySoul;
private final List<ZLTextElementArea> myList;
// this field must be accessed in synchronized context only
private final List<ZLTextElementArea> myAreaList;
private ZLTextElementArea[] myAreas;
private final int myFromIndex;
private int myToIndex;
private ZLTextHorizontalConvexHull myHull;
ZLTextRegion(Soul soul, List<ZLTextElementArea> list, int fromIndex) {
mySoul = soul;
myList = list;
myAreaList = list;
myFromIndex = fromIndex;
myToIndex = fromIndex + 1;
}
@ -128,8 +130,16 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
return mySoul;
}
private List<ZLTextElementArea> textAreas() {
return myList.subList(myFromIndex, myToIndex);
private ZLTextElementArea[] textAreas() {
if (myAreas == null || myAreas.length != myToIndex - myFromIndex) {
synchronized (myAreaList) {
myAreas = new ZLTextElementArea[myToIndex - myFromIndex];
for (int i = 0; i < myAreas.length; ++i) {
myAreas[i] = myAreaList.get(i + myFromIndex);
}
}
}
return myAreas;
}
private ZLTextHorizontalConvexHull convexHull() {
if (myHull == null) {
@ -139,11 +149,12 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
}
ZLTextElementArea getFirstArea() {
return myList.get(myFromIndex);
return textAreas()[0];
}
ZLTextElementArea getLastArea() {
return myList.get(myToIndex - 1);
final ZLTextElementArea[] areas = textAreas();
return areas[areas.length - 1];
}
public int getTop() {
@ -189,8 +200,8 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
if (!isUnder(other)) {
return false;
}
final List<ZLTextElementArea> areas0 = textAreas();
final List<ZLTextElementArea> areas1 = other.textAreas();
final ZLTextElementArea[] areas0 = textAreas();
final ZLTextElementArea[] areas1 = other.textAreas();
for (ZLTextElementArea i : areas0) {
for (ZLTextElementArea j : areas1) {
if (i.XStart <= j.XEnd && j.XStart <= i.XEnd) {
@ -204,16 +215,4 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
boolean isExactlyOver(ZLTextRegion other) {
return other == null || other.isExactlyUnder(this);
}
/*
public int compareTo(ZLTextRegion other) {
if (myFromIndex != other.myFromIndex) {
return myFromIndex < other.myFromIndex ? -1 : 1;
}
if (myToIndex != other.myToIndex) {
return myToIndex < other.myToIndex ? -1 : 1;
}
return 0;
}
*/
}

View file

@ -20,13 +20,27 @@
package org.geometerplus.zlibrary.text.view;
public class ZLTextSelection {
static class Point {
int X;
int Y;
Point(int x, int y) {
X = x;
Y = y;
}
}
private final ZLTextView myView;
private ZLTextRegion.Soul myLeftMostRegionSoul;
private ZLTextRegion.Soul myRightMostRegionSoul;
private ZLTextSelectionCursor myCursorInMovement = ZLTextSelectionCursor.None;
private final Point myCursorInMovementPoint = new Point(-1, -1);
private Scroller myScroller;
ZLTextSelection(ZLTextView view) {
myView = view;
}
@ -43,9 +57,24 @@ public class ZLTextSelection {
stop();
myLeftMostRegionSoul = null;
myRightMostRegionSoul = null;
myCursorInMovement = ZLTextSelectionCursor.None;
return true;
}
void setCursorInMovement(ZLTextSelectionCursor cursor, int x, int y) {
myCursorInMovement = cursor;
myCursorInMovementPoint.X = x;
myCursorInMovementPoint.Y = y;
}
ZLTextSelectionCursor getCursorInMovement() {
return myCursorInMovement;
}
Point getCursorInMovementPoint() {
return myCursorInMovementPoint;
}
boolean start(int x, int y) {
clear();
@ -61,35 +90,36 @@ public class ZLTextSelection {
}
void stop() {
myCursorInMovement = ZLTextSelectionCursor.None;
if (myScroller != null) {
myScroller.stop();
myScroller = null;
}
}
ZLTextSelectionCursor expandTo(int x, int y, ZLTextSelectionCursor cursorToMove) {
void expandTo(int x, int y) {
if (isEmpty()) {
return cursorToMove;
return;
}
/*
if (y < 10) {
final ZLTextElementAreaVector vector = myView.myCurrentPage.TextElementMap;
if (!vector.isEmpty() && y < vector.get(0).YStart) {
if (myScroller != null && myScroller.scrollsForward()) {
myScroller.stop();
myScroller = null;
}
if (myScroller == null) {
myScroller = new Scroller(false, x, y);
return false;
return;
}
} else if (y > myView.getTextAreaHeight() - 10) {
} else if (!vector.isEmpty() && y + ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2 > vector.get(vector.size() - 1).YEnd) {
if (myScroller != null && !myScroller.scrollsForward()) {
myScroller.stop();
myScroller = null;
}
if (myScroller == null) {
myScroller = new Scroller(true, x, y);
return false;
return;
}
} else {
if (myScroller != null) {
@ -101,34 +131,45 @@ public class ZLTextSelection {
if (myScroller != null) {
myScroller.setXY(x, y);
}
*/
ZLTextRegion region = myView.findRegion(x, y, ZLTextView.MAX_SELECTION_DISTANCE, ZLTextRegion.AnyRegionFilter);
if (region == null && myScroller != null) {
region = myView.findRegion(x, y, ZLTextRegion.AnyRegionFilter);
}
if (region == null) {
return cursorToMove;
return;
}
final ZLTextRegion.Soul soul = region.getSoul();
if (cursorToMove == ZLTextSelectionCursor.Right) {
if (myCursorInMovement == ZLTextSelectionCursor.Right) {
if (myLeftMostRegionSoul.compareTo(soul) <= 0) {
myRightMostRegionSoul = soul;
return cursorToMove;
} else {
myRightMostRegionSoul = myLeftMostRegionSoul;
myLeftMostRegionSoul = soul;
return ZLTextSelectionCursor.Left;
myCursorInMovement = ZLTextSelectionCursor.Left;
}
} else {
if (myRightMostRegionSoul.compareTo(soul) >= 0) {
myLeftMostRegionSoul = soul;
return cursorToMove;
} else {
myLeftMostRegionSoul = myRightMostRegionSoul;
myRightMostRegionSoul = soul;
return ZLTextSelectionCursor.Right;
myCursorInMovement = ZLTextSelectionCursor.Right;
}
}
if (myCursorInMovement == ZLTextSelectionCursor.Right) {
if (hasAPartAfterPage(myView.myCurrentPage)) {
myView.scrollPage(true, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
myView.Application.getViewWidget().reset();
myView.preparePaintInfo();
}
} else {
if (hasAPartBeforePage(myView.myCurrentPage)) {
myView.scrollPage(false, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
myView.Application.getViewWidget().reset();
myView.preparePaintInfo();
}
}
}
@ -174,7 +215,7 @@ public class ZLTextSelection {
if (region != null) {
return region.getFirstArea();
}
if (myRightMostRegionSoul.compareTo(vector.get(0)) >= 0) {
if (myLeftMostRegionSoul.compareTo(vector.get(0)) <= 0) {
return vector.get(0);
}
return null;
@ -246,7 +287,7 @@ public class ZLTextSelection {
public void run() {
myView.scrollPage(myScrollForward, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
myView.preparePaintInfo();
//expandTo(myX, myY, myScrollForward);
expandTo(myX, myY);
myView.Application.getViewWidget().reset();
myView.Application.getViewWidget().repaint();
}

View file

@ -218,6 +218,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
myNextPage.reset();
myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);
myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;
Application.getViewWidget().reset();
}
break;
}
@ -238,46 +239,31 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
}
private static class Point {
int X;
int Y;
Point(int x, int y) {
X = x;
Y = y;
}
}
private ZLTextSelectionCursor mySelectionCursorInMovement = ZLTextSelectionCursor.None;
private final Point myMovedSelectionCursorPoint = new Point(-1, -1);
protected void moveSelectionCursorTo(ZLTextSelectionCursor cursor, int x, int y) {
y -= ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2;
mySelectionCursorInMovement = mySelection.expandTo(x, y, cursor);
myMovedSelectionCursorPoint.X = x;
myMovedSelectionCursorPoint.Y = y;
mySelection.setCursorInMovement(cursor, x, y);
mySelection.expandTo(x, y);
Application.getViewWidget().reset();
Application.getViewWidget().repaint();
}
protected void releaseSelectionCursor() {
mySelectionCursorInMovement = ZLTextSelectionCursor.None;
mySelection.stop();
Application.getViewWidget().reset();
Application.getViewWidget().repaint();
}
protected ZLTextSelectionCursor getSelectionCursorInMovement() {
return mySelectionCursorInMovement;
return mySelection.getCursorInMovement();
}
private Point getSelectionCursorPoint(ZLTextPage page, ZLTextSelectionCursor cursor) {
private ZLTextSelection.Point getSelectionCursorPoint(ZLTextPage page, ZLTextSelectionCursor cursor) {
if (cursor == ZLTextSelectionCursor.None) {
return null;
}
if (cursor == mySelectionCursorInMovement) {
return myMovedSelectionCursorPoint;
if (cursor == mySelection.getCursorInMovement()) {
return mySelection.getCursorInMovementPoint();
}
if (cursor == ZLTextSelectionCursor.Left) {
@ -286,7 +272,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
final ZLTextElementArea selectionStartArea = mySelection.getStartArea(page);
if (selectionStartArea != null) {
return new Point(selectionStartArea.XStart, selectionStartArea.YEnd);
return new ZLTextSelection.Point(selectionStartArea.XStart, selectionStartArea.YEnd);
}
} else {
if (mySelection.hasAPartAfterPage(page)) {
@ -294,13 +280,13 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
final ZLTextElementArea selectionEndArea = mySelection.getEndArea(page);
if (selectionEndArea != null) {
return new Point(selectionEndArea.XEnd, selectionEndArea.YEnd);
return new ZLTextSelection.Point(selectionEndArea.XEnd, selectionEndArea.YEnd);
}
}
return null;
}
private int distanceToCursor(int x, int y, Point cursorPoint) {
private int distanceToCursor(int x, int y, ZLTextSelection.Point cursorPoint) {
if (cursorPoint == null) {
return Integer.MAX_VALUE;
}
@ -351,7 +337,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
}
private void drawSelectionCursor(ZLPaintContext context, Point pt) {
private void drawSelectionCursor(ZLPaintContext context, ZLTextSelection.Point pt) {
if (pt == null) {
return;
}
@ -999,7 +985,11 @@ public abstract class ZLTextView extends ZLTextViewBase {
if (getTextStyle().isUnderline()) {
spaceElement = new ZLTextElementArea(
paragraphIndex, wordIndex, 0,
0, false, false, getTextStyle(), element, x, x + spaceLength, y, y
0, // length
true, // is last in element
false, // add hyphenation sign
false, // changed style
getTextStyle(), element, x, x + spaceLength, y, y
);
} else {
spaceElement = null;
@ -1017,8 +1007,14 @@ public abstract class ZLTextView extends ZLTextViewBase {
page.TextElementMap.add(spaceElement);
spaceElement = null;
}
page.TextElementMap.add(new ZLTextElementArea(paragraphIndex, wordIndex, charIndex,
length - charIndex, false, changeStyle, getTextStyle(), element, x, x + width - 1, y - height + 1, y + descent));
page.TextElementMap.add(new ZLTextElementArea(
paragraphIndex, wordIndex, charIndex,
length - charIndex,
true, // is last in element
false, // add hyphenation sign
changeStyle, getTextStyle(), element,
x, x + width - 1, y - height + 1, y + descent
));
changeStyle = false;
wordOccurred = true;
} else if (element instanceof ZLTextControlElement) {
@ -1039,7 +1035,9 @@ public abstract class ZLTextView extends ZLTextViewBase {
page.TextElementMap.add(
new ZLTextElementArea(
paragraphIndex, wordIndex, 0,
len, addHyphenationSign,
len,
false, // is last in element
addHyphenationSign,
changeStyle, getTextStyle(), word,
x, x + width - 1, y - height + 1, y + descent
)
@ -1372,18 +1370,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
protected ZLTextRegion findRegion(int x, int y, int maxDistance, ZLTextRegion.Filter filter) {
ZLTextRegion bestRegion = null;
int distance = maxDistance + 1;
for (ZLTextRegion region : myCurrentPage.TextElementMap.elementRegions()) {
if (filter.accepts(region)) {
final int d = region.distanceTo(x, y);
if (d < distance) {
bestRegion = region;
distance = d;
}
}
}
return bestRegion;
return myCurrentPage.TextElementMap.findRegion(x, y, maxDistance, filter);
}
protected void selectRegion(ZLTextRegion region) {
@ -1405,8 +1392,6 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
public void clearSelection() {
mySelectionCursorInMovement = ZLTextSelectionCursor.None;
mySelection.stop();
if (mySelection.clear()) {
Application.getViewWidget().reset();
Application.getViewWidget().repaint();
@ -1463,92 +1448,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
}
protected ZLTextRegion nextRegion(Direction direction, ZLTextRegion.Filter filter) {
final List<ZLTextRegion> elementRegions = myCurrentPage.TextElementMap.elementRegions();
if (elementRegions.isEmpty()) {
return null;
}
final ZLTextRegion selectedRegion = getSelectedRegion();
int index = selectedRegion != null ? elementRegions.indexOf(selectedRegion) : -1;
switch (direction) {
case rightToLeft:
case up:
if (index == -1) {
index = elementRegions.size() - 1;
} else if (index == 0) {
return null;
} else {
--index;
}
break;
case leftToRight:
case down:
if (index == elementRegions.size() - 1) {
return null;
} else {
++index;
}
break;
}
switch (direction) {
case rightToLeft:
for (; index >= 0; --index) {
final ZLTextRegion candidate = elementRegions.get(index);
if (filter.accepts(candidate) && candidate.isAtLeftOf(selectedRegion)) {
return candidate;
}
}
break;
case leftToRight:
for (; index < elementRegions.size(); ++index) {
final ZLTextRegion candidate = elementRegions.get(index);
if (filter.accepts(candidate) && candidate.isAtRightOf(selectedRegion)) {
return candidate;
}
}
break;
case down:
{
ZLTextRegion firstCandidate = null;
for (; index < elementRegions.size(); ++index) {
final ZLTextRegion candidate = elementRegions.get(index);
if (!filter.accepts(candidate)) {
continue;
}
if (candidate.isExactlyUnder(selectedRegion)) {
return candidate;
}
if (firstCandidate == null && candidate.isUnder(selectedRegion)) {
firstCandidate = candidate;
}
}
if (firstCandidate != null) {
return firstCandidate;
}
break;
}
case up:
ZLTextRegion firstCandidate = null;
for (; index >= 0; --index) {
final ZLTextRegion candidate = elementRegions.get(index);
if (!filter.accepts(candidate)) {
continue;
}
if (candidate.isExactlyOver(selectedRegion)) {
return candidate;
}
if (firstCandidate == null && candidate.isOver(selectedRegion)) {
firstCandidate = candidate;
}
}
if (firstCandidate != null) {
return firstCandidate;
}
break;
}
return null;
return myCurrentPage.TextElementMap.nextRegion(getSelectedRegion(), direction, filter);
}
@Override

View file

@ -91,7 +91,8 @@ abstract class ZLTextViewBase extends ZLView {
void applyControl(ZLTextControlElement control) {
if (control.IsStart) {
ZLTextStyleDecoration decoration = ZLTextStyleCollection.Instance().getDecoration(control.Kind);
final ZLTextStyleDecoration decoration =
ZLTextStyleCollection.Instance().getDecoration(control.Kind);
if (control instanceof ZLTextHyperlinkControlElement) {
setTextStyle(decoration.createDecoratedStyle(myTextStyle, ((ZLTextHyperlinkControlElement)control).Hyperlink));
} else {

View file

@ -30,8 +30,8 @@ abstract class AnimationProvider {
static enum Mode {
NoScrolling(false),
ManualScrolling(false),
AutoScrollingForward(true),
AutoScrollingBackward(true);
AnimatedScrollingForward(true),
AnimatedScrollingBackward(true);
final boolean Auto;
@ -81,7 +81,7 @@ abstract class AnimationProvider {
}
}
void startAutoScrolling(int x, int y, int speed) {
void startAnimatedScrolling(int x, int y, int speed) {
if (myMode != Mode.ManualScrolling) {
return;
}
@ -96,7 +96,7 @@ abstract class AnimationProvider {
(myHeight > myWidth ? myHeight / 4 : myHeight / 3);
boolean forward = Math.abs(diff) > minDiff;
myMode = forward ? Mode.AutoScrollingForward : Mode.AutoScrollingBackward;
myMode = forward ? Mode.AnimatedScrollingForward : Mode.AnimatedScrollingBackward;
float velocity = 15;
if (myDrawInfos.size() > 1) {
@ -136,16 +136,16 @@ abstract class AnimationProvider {
break;
}
startAutoScrollingInternal(speed);
startAnimatedScrollingInternal(speed);
}
public void startAutoScrolling(ZLView.PageIndex pageIndex, Integer x, Integer y, int speed) {
public void startAnimatedScrolling(ZLView.PageIndex pageIndex, Integer x, Integer y, int speed) {
if (myMode.Auto) {
return;
}
terminate();
myMode = Mode.AutoScrollingForward;
myMode = Mode.AnimatedScrollingForward;
switch (myDirection) {
case up:
@ -157,12 +157,12 @@ abstract class AnimationProvider {
mySpeed = pageIndex == ZLView.PageIndex.next ? 15 : -15;
break;
}
setupAutoScrollingStart(x, y);
startAutoScrollingInternal(speed);
setupAnimatedScrollingStart(x, y);
startAnimatedScrollingInternal(speed);
}
protected abstract void startAutoScrollingInternal(int speed);
protected abstract void setupAutoScrollingStart(Integer x, Integer y);
protected abstract void startAnimatedScrollingInternal(int speed);
protected abstract void setupAnimatedScrollingStart(Integer x, Integer y);
boolean inProgress() {
return myMode != Mode.NoScrolling;

View file

@ -199,14 +199,14 @@ class CurlAnimationProvider extends AnimationProvider {
}
@Override
protected void startAutoScrollingInternal(int speed) {
protected void startAnimatedScrollingInternal(int speed) {
mySpeedFactor = (float)Math.pow(2.0, 0.25 * speed);
mySpeed *= 1.5;
doStep();
}
@Override
protected void setupAutoScrollingStart(Integer x, Integer y) {
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
if (x == null || y == null) {
if (myDirection.IsHorizontal) {
x = mySpeed < 0 ? myWidth - 3 : 3;
@ -245,7 +245,7 @@ class CurlAnimationProvider extends AnimationProvider {
final int cornerY = myStartY > myHeight / 2 ? myHeight : 0;
final int boundX, boundY;
if (getMode() == Mode.AutoScrollingForward) {
if (getMode() == Mode.AnimatedScrollingForward) {
boundX = cornerX == 0 ? 2 * myWidth : -myWidth;
boundY = cornerY == 0 ? 2 * myHeight : -myHeight;
} else {
@ -268,7 +268,7 @@ class CurlAnimationProvider extends AnimationProvider {
}
final boolean xSpeedIsPositive, ySpeedIsPositive;
if (getMode() == Mode.AutoScrollingForward) {
if (getMode() == Mode.AnimatedScrollingForward) {
xSpeedIsPositive = cornerX == 0;
ySpeedIsPositive = cornerY == 0;
} else {

View file

@ -43,7 +43,7 @@ class NoneAnimationProvider extends AnimationProvider {
}
@Override
protected void setupAutoScrollingStart(Integer x, Integer y) {
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
if (myDirection.IsHorizontal) {
myStartX = mySpeed < 0 ? myWidth : 0;
myEndX = myWidth - myStartX;
@ -56,7 +56,7 @@ class NoneAnimationProvider extends AnimationProvider {
}
@Override
protected void startAutoScrollingInternal(int speed) {
protected void startAnimatedScrollingInternal(int speed) {
}
@Override

View file

@ -48,7 +48,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
}
@Override
protected void setupAutoScrollingStart(Integer x, Integer y) {
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
if (x == null || y == null) {
if (myDirection.IsHorizontal) {
x = mySpeed < 0 ? myWidth : 0;
@ -63,7 +63,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
}
@Override
protected void startAutoScrollingInternal(int speed) {
protected void startAnimatedScrollingInternal(int speed) {
mySpeedFactor = (float)Math.pow(1.5, 0.25 * speed);
doStep();
}
@ -89,7 +89,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
break;
}
final int bound;
if (getMode() == Mode.AutoScrollingForward) {
if (getMode() == Mode.AnimatedScrollingForward) {
bound = myDirection.IsHorizontal ? myWidth : myHeight;
} else {
bound = 0;

View file

@ -132,7 +132,7 @@ public class ZLAndroidWidget extends View implements ZLViewWidget, View.OnLongCl
drawFooter(canvas);
} else {
switch (oldMode) {
case AutoScrollingForward:
case AnimatedScrollingForward:
{
final ZLView.PageIndex index = animator.getPageToScrollTo();
myBitmapManager.shift(index == ZLView.PageIndex.next);
@ -140,7 +140,7 @@ public class ZLAndroidWidget extends View implements ZLViewWidget, View.OnLongCl
ZLApplication.Instance().onRepaintFinished();
break;
}
case AutoScrollingBackward:
case AnimatedScrollingBackward:
view.onScrollingFinished(ZLView.PageIndex.current);
break;
}
@ -171,40 +171,40 @@ public class ZLAndroidWidget extends View implements ZLViewWidget, View.OnLongCl
}
}
public void startAutoScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed) {
public void startAnimatedScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed) {
final ZLView view = ZLApplication.Instance().getCurrentView();
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
return;
}
final AnimationProvider animator = getAnimationProvider();
animator.setup(direction, getWidth(), getMainAreaHeight());
animator.startAutoScrolling(pageIndex, x, y, speed);
animator.startAnimatedScrolling(pageIndex, x, y, speed);
if (animator.getMode().Auto) {
postInvalidate();
}
}
public void startAutoScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed) {
public void startAnimatedScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed) {
final ZLView view = ZLApplication.Instance().getCurrentView();
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
return;
}
final AnimationProvider animator = getAnimationProvider();
animator.setup(direction, getWidth(), getMainAreaHeight());
animator.startAutoScrolling(pageIndex, null, null, speed);
animator.startAnimatedScrolling(pageIndex, null, null, speed);
if (animator.getMode().Auto) {
postInvalidate();
}
}
public void startAutoScrolling(int x, int y, int speed) {
public void startAnimatedScrolling(int x, int y, int speed) {
final ZLView view = ZLApplication.Instance().getCurrentView();
final AnimationProvider animator = getAnimationProvider();
if (!view.canScroll(animator.getPageToScrollTo(x, y))) {
animator.terminate();
return;
}
animator.startAutoScrolling(x, y, speed);
animator.startAnimatedScrolling(x, y, speed);
postInvalidate();
}