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:
commit
148c442f39
49 changed files with 512 additions and 298 deletions
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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" />
|
<uses-sdk android:minSdkVersion="4" />
|
||||||
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
|
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
===== 1.1.0 (Jun ??, 2011) =====
|
===== 1.2.0 (??? ??, 2011) =====
|
||||||
* Text selection
|
|
||||||
|
===== 1.1.0 (Jun 11, 2011) =====
|
||||||
|
* Text selection (original code by Dmitry Gordeev)
|
||||||
* Localization to Traditional Chinese (by Fung.T)
|
* Localization to Traditional Chinese (by Fung.T)
|
||||||
|
|
||||||
===== 1.0.12 (May 13, 2011) =====
|
===== 1.0.12 (May 13, 2011) =====
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
1.1.0
|
1.2.0
|
||||||
|
|
|
@ -542,6 +542,7 @@
|
||||||
<node name="dictionary" value="Slovník">
|
<node name="dictionary" value="Slovník">
|
||||||
<node name="summary" value="Nastavení slovníku"/>
|
<node name="summary" value="Nastavení slovníku"/>
|
||||||
<node name="dictionary" value="Slovník"/>
|
<node name="dictionary" value="Slovník"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="Dlouhé klepnutí">
|
<node name="tappingAction" value="Dlouhé klepnutí">
|
||||||
<node name="doNothing" value="Dlouhé klepnutí nedělá nic"/>
|
<node name="doNothing" value="Dlouhé klepnutí nedělá nic"/>
|
||||||
<node name="selectSingleWord" value="Dlouhé klepnutí vybere slovo"/>
|
<node name="selectSingleWord" value="Dlouhé klepnutí vybere slovo"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
||||||
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
||||||
<node name="dictionary" value="Dictionary" 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="tappingAction" value="Long tapping action" toBeTranslated="true">
|
||||||
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
||||||
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
||||||
|
|
|
@ -543,6 +543,7 @@
|
||||||
<node name="dictionary" value="Dictionary">
|
<node name="dictionary" value="Dictionary">
|
||||||
<node name="summary" value="Dictionary settings"/>
|
<node name="summary" value="Dictionary settings"/>
|
||||||
<node name="dictionary" value="Dictionary"/>
|
<node name="dictionary" value="Dictionary"/>
|
||||||
|
<node name="translator" value="Translator"/>
|
||||||
<node name="tappingAction" value="Long tapping action">
|
<node name="tappingAction" value="Long tapping action">
|
||||||
<node name="doNothing" value="Long tapping does nothing"/>
|
<node name="doNothing" value="Long tapping does nothing"/>
|
||||||
<node name="selectSingleWord" value="Long tapping selects single word"/>
|
<node name="selectSingleWord" value="Long tapping selects single word"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Dictionnaire">
|
<node name="dictionary" value="Dictionnaire">
|
||||||
<node name="summary" value="Paramètres du dictionnaire"/>
|
<node name="summary" value="Paramètres du dictionnaire"/>
|
||||||
<node name="dictionary" value="Dictionnaire"/>
|
<node name="dictionary" value="Dictionnaire"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="Configuration de l'appui long">
|
<node name="tappingAction" value="Configuration de l'appui long">
|
||||||
<node name="doNothing" value="Un appui long ne fait rien"/>
|
<node name="doNothing" value="Un appui long ne fait rien"/>
|
||||||
<node name="selectSingleWord" value="Un appui long selectionne le mot"/>
|
<node name="selectSingleWord" value="Un appui long selectionne le mot"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Dicionario">
|
<node name="dictionary" value="Dicionario">
|
||||||
<node name="summary" value="Preferencias do dicionario"/>
|
<node name="summary" value="Preferencias do dicionario"/>
|
||||||
<node name="dictionary" value="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="tappingAction" value="Acción de pulsación longa">
|
||||||
<node name="doNothing" value="Pulsación longa non fai nada"/>
|
<node name="doNothing" value="Pulsación longa non fai nada"/>
|
||||||
<node name="selectSingleWord" value="Pulsación longa selecciona a palabra"/>
|
<node name="selectSingleWord" value="Pulsación longa selecciona a palabra"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Szótár">
|
<node name="dictionary" value="Szótár">
|
||||||
<node name="summary" value="Szótár beállításai"/>
|
<node name="summary" value="Szótár beállításai"/>
|
||||||
<node name="dictionary" value="Szótár"/>
|
<node name="dictionary" value="Szótár"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="Hosszú érintés">
|
<node name="tappingAction" value="Hosszú érintés">
|
||||||
<node name="doNothing" value="Nem történik semmi hosszú érintésre"/>
|
<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"/>
|
<node name="selectSingleWord" value="A hosszú érintés kijelöli a szót"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
||||||
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
||||||
<node name="dictionary" value="Dictionary" 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="tappingAction" value="Long tapping action" toBeTranslated="true">
|
||||||
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
||||||
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Woordenboek">
|
<node name="dictionary" value="Woordenboek">
|
||||||
<node name="summary" value="Woordenboek instellingen"/>
|
<node name="summary" value="Woordenboek instellingen"/>
|
||||||
<node name="dictionary" value="Woordenboek"/>
|
<node name="dictionary" value="Woordenboek"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
|
<node name="tappingAction" value="Long tapping action" toBeTranslated="true">
|
||||||
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
||||||
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Словарь">
|
<node name="dictionary" value="Словарь">
|
||||||
<node name="summary" value="Настройки словаря"/>
|
<node name="summary" value="Настройки словаря"/>
|
||||||
<node name="dictionary" value="Словарь"/>
|
<node name="dictionary" value="Словарь"/>
|
||||||
|
<node name="translator" value="Переводчик"/>
|
||||||
<node name="tappingAction" value="Действие при долгом нажатии на экран">
|
<node name="tappingAction" value="Действие при долгом нажатии на экран">
|
||||||
<node name="doNothing" value="Ничего не делать"/>
|
<node name="doNothing" value="Ничего не делать"/>
|
||||||
<node name="selectSingleWord" value="Выделять одно слово"/>
|
<node name="selectSingleWord" value="Выделять одно слово"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="พจนานุกรม">
|
<node name="dictionary" value="พจนานุกรม">
|
||||||
<node name="summary" value="การตั้งค่าพจนานุกรม"/>
|
<node name="summary" value="การตั้งค่าพจนานุกรม"/>
|
||||||
<node name="dictionary" value="พจนานุกรม"/>
|
<node name="dictionary" value="พจนานุกรม"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="การทำงานเมื่อกดค้างที่หน้าจอ">
|
<node name="tappingAction" value="การทำงานเมื่อกดค้างที่หน้าจอ">
|
||||||
<node name="doNothing" value="ไม่มีอะไรเกิดขึ้น"/>
|
<node name="doNothing" value="ไม่มีอะไรเกิดขึ้น"/>
|
||||||
<node name="selectSingleWord" value="เลือกคำเมื่อกดค้างที่หน้าจอ"/>
|
<node name="selectSingleWord" value="เลือกคำเมื่อกดค้างที่หน้าจอ"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
<node name="dictionary" value="Dictionary" toBeTranslated="true">
|
||||||
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
<node name="summary" value="Dictionary settings" toBeTranslated="true"/>
|
||||||
<node name="dictionary" value="Dictionary" 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="tappingAction" value="Long tapping action" toBeTranslated="true">
|
||||||
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
<node name="doNothing" value="Long tapping does nothing" toBeTranslated="true"/>
|
||||||
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
<node name="selectSingleWord" value="Long tapping selects single word" toBeTranslated="true"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="Từ điển">
|
<node name="dictionary" value="Từ điển">
|
||||||
<node name="summary" value="Cài đặt từ điển"/>
|
<node name="summary" value="Cài đặt từ điển"/>
|
||||||
<node name="dictionary" value="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="tappingAction" value="Nhấn giữ">
|
||||||
<node name="doNothing" value="Không làm gì khi 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ữ"/>
|
<node name="selectSingleWord" value="Chọn từ khi nhấn giữ"/>
|
||||||
|
|
|
@ -528,6 +528,7 @@
|
||||||
<node name="dictionary" value="字典">
|
<node name="dictionary" value="字典">
|
||||||
<node name="summary" value="字典设定"/>
|
<node name="summary" value="字典设定"/>
|
||||||
<node name="dictionary" value="字典"/>
|
<node name="dictionary" value="字典"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="长拍触行为动作">
|
<node name="tappingAction" value="长拍触行为动作">
|
||||||
<node name="doNothing" value="长拍触不做任何动作"/>
|
<node name="doNothing" value="长拍触不做任何动作"/>
|
||||||
<node name="selectSingleWord" value="长拍触选择词语"/>
|
<node name="selectSingleWord" value="长拍触选择词语"/>
|
||||||
|
|
|
@ -547,6 +547,7 @@
|
||||||
<node name="dictionary" value="字典">
|
<node name="dictionary" value="字典">
|
||||||
<node name="summary" value="字典設定"/>
|
<node name="summary" value="字典設定"/>
|
||||||
<node name="dictionary" value="字典"/>
|
<node name="dictionary" value="字典"/>
|
||||||
|
<node name="translator" value="Translator" toBeTranslated="true"/>
|
||||||
<node name="tappingAction" value="長按動作">
|
<node name="tappingAction" value="長按動作">
|
||||||
<node name="doNothing" value="長按不做任何動作"/>
|
<node name="doNothing" value="長按不做任何動作"/>
|
||||||
<node name="selectSingleWord" value="長按選字"/>
|
<node name="selectSingleWord" value="長按選字"/>
|
||||||
|
|
|
@ -10,4 +10,4 @@
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-8
|
target=android-8
|
||||||
java.encoding=utf-8
|
java.encoding=utf-8
|
||||||
#proguard.config=proguard.cfg
|
proguard.config=proguard.cfg
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_pressed="true" android:drawable="@drawable/selection_dictionary_active" />
|
<item android:state_pressed="true" android:drawable="@drawable/selection_translate_active" />
|
||||||
<item android:drawable="@drawable/selection_dictionary_default" />
|
<item android:drawable="@drawable/selection_translate_default" />
|
||||||
</selector>
|
</selector>
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -45,7 +45,8 @@ public abstract class DictionaryUtil {
|
||||||
// Map: dictionary info -> hide if package is not installed
|
// Map: dictionary info -> hide if package is not installed
|
||||||
private static LinkedHashMap<PackageInfo,Boolean> ourDictionaryInfos =
|
private static LinkedHashMap<PackageInfo,Boolean> ourDictionaryInfos =
|
||||||
new LinkedHashMap<PackageInfo,Boolean>();
|
new LinkedHashMap<PackageInfo,Boolean>();
|
||||||
private static ZLStringOption ourDictionaryOption;
|
private static ZLStringOption ourSingleWordTranslatorOption;
|
||||||
|
private static ZLStringOption ourMultiWordTranslatorOption;
|
||||||
|
|
||||||
private static class InfoReader extends ZLXMLReaderAdapter {
|
private static class InfoReader extends ZLXMLReaderAdapter {
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,15 +114,24 @@ public abstract class DictionaryUtil {
|
||||||
throw new RuntimeException("There are no available dictionary infos");
|
throw new RuntimeException("There are no available dictionary infos");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ZLStringOption dictionaryOption() {
|
public static ZLStringOption singleWordTranslatorOption() {
|
||||||
if (ourDictionaryOption == null) {
|
if (ourSingleWordTranslatorOption == null) {
|
||||||
ourDictionaryOption = new ZLStringOption("Dictionary", "Id", firstInfo().Id);
|
ourSingleWordTranslatorOption = new ZLStringOption("Dictionary", "Id", firstInfo().Id);
|
||||||
}
|
}
|
||||||
return ourDictionaryOption;
|
return ourSingleWordTranslatorOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PackageInfo getCurrentDictionaryInfo() {
|
public static ZLStringOption multiWordTranslatorOption() {
|
||||||
final String id = dictionaryOption().getValue();
|
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()) {
|
for (PackageInfo info : infos().keySet()) {
|
||||||
if (info.Id.equals(id)) {
|
if (info.Id.equals(id)) {
|
||||||
return info;
|
return info;
|
||||||
|
@ -130,8 +140,8 @@ public abstract class DictionaryUtil {
|
||||||
return firstInfo();
|
return firstInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Intent getDictionaryIntent(String text) {
|
private static Intent getDictionaryIntent(String text, boolean singleWord) {
|
||||||
return getDictionaryIntent(getCurrentDictionaryInfo(), text);
|
return getDictionaryIntent(getCurrentDictionaryInfo(singleWord), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent getDictionaryIntent(PackageInfo dictionaryInfo, String 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) {
|
public static void openTextInDictionary(Activity activity, String text, boolean singleWord, int selectionTop, int selectionBottom) {
|
||||||
final PackageInfo info = getCurrentDictionaryInfo();
|
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);
|
final Intent intent = getDictionaryIntent(info, text);
|
||||||
try {
|
try {
|
||||||
if ("ColorDict".equals(info.Id)) {
|
if ("ColorDict".equals(info.Id)) {
|
||||||
|
@ -175,30 +196,21 @@ public abstract class DictionaryUtil {
|
||||||
}
|
}
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
DictionaryUtil.installDictionaryIfNotInstalled(activity);
|
DictionaryUtil.installDictionaryIfNotInstalled(activity, singleWord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openWordInDictionary(Activity activity, ZLTextWord word, ZLTextRegion region) {
|
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(
|
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) {
|
public static void installDictionaryIfNotInstalled(final Activity activity, boolean singleWord) {
|
||||||
if (PackageUtil.canBeStarted(activity, getDictionaryIntent("test"), false)) {
|
if (PackageUtil.canBeStarted(activity, getDictionaryIntent("test", singleWord), false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PackageInfo dictionaryInfo = getCurrentDictionaryInfo();
|
final PackageInfo dictionaryInfo = getCurrentDictionaryInfo(singleWord);
|
||||||
|
|
||||||
final ZLResource dialogResource = ZLResource.resource("dialog");
|
final ZLResource dialogResource = ZLResource.resource("dialog");
|
||||||
final ZLResource buttonResource = dialogResource.getResource("button");
|
final ZLResource buttonResource = dialogResource.getResource("button");
|
||||||
|
|
|
@ -101,8 +101,8 @@ public final class FBReader extends ZLAndroidActivity {
|
||||||
fbReader.addAction(ActionCode.SELECTION_HIDE_PANEL, new SelectionHidePanelAction(this, fbReader));
|
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_COPY_TO_CLIPBOARD, new SelectionCopyAction(this, fbReader));
|
||||||
fbReader.addAction(ActionCode.SELECTION_SHARE, new SelectionShareAction(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_TRANSLATE, new SelectionTranslateAction(this, fbReader));
|
||||||
fbReader.addAction(ActionCode.SELECTION_ADD_BOOKMARK, new SelectionBookmarkAction(this, fbReader));
|
fbReader.addAction(ActionCode.SELECTION_BOOKMARK, new SelectionBookmarkAction(this, fbReader));
|
||||||
|
|
||||||
fbReader.addAction(ActionCode.PROCESS_HYPERLINK, new ProcessHyperlinkAction(this, fbReader));
|
fbReader.addAction(ActionCode.PROCESS_HYPERLINK, new ProcessHyperlinkAction(this, fbReader));
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,8 @@ class SelectionPopup extends ButtonsPopupPanel {
|
||||||
|
|
||||||
addButton(ActionCode.SELECTION_COPY_TO_CLIPBOARD, true, R.drawable.selection_copy);
|
addButton(ActionCode.SELECTION_COPY_TO_CLIPBOARD, true, R.drawable.selection_copy);
|
||||||
addButton(ActionCode.SELECTION_SHARE, true, R.drawable.selection_share);
|
addButton(ActionCode.SELECTION_SHARE, true, R.drawable.selection_share);
|
||||||
addButton(ActionCode.SELECTION_OPEN_IN_DICTIONARY, true, R.drawable.selection_dictionary);
|
addButton(ActionCode.SELECTION_TRANSLATE, true, R.drawable.selection_translate);
|
||||||
addButton(ActionCode.SELECTION_ADD_BOOKMARK, true, R.drawable.selection_bookmark);
|
addButton(ActionCode.SELECTION_BOOKMARK, true, R.drawable.selection_bookmark);
|
||||||
addButton(ActionCode.SELECTION_CLEAR, true, R.drawable.selection_close);
|
addButton(ActionCode.SELECTION_CLEAR, true, R.drawable.selection_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +69,10 @@ class SelectionPopup extends ButtonsPopupPanel {
|
||||||
final int diffTop = screenHeight - selectionEndY;
|
final int diffTop = screenHeight - selectionEndY;
|
||||||
final int diffBottom = selectionStartY;
|
final int diffBottom = selectionStartY;
|
||||||
if (diffTop > diffBottom) {
|
if (diffTop > diffBottom) {
|
||||||
verticalPosition = diffTop > myWindow.getHeight() + 10
|
verticalPosition = diffTop > myWindow.getHeight() + 20
|
||||||
? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.CENTER_VERTICAL;
|
? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.CENTER_VERTICAL;
|
||||||
} else {
|
} else {
|
||||||
verticalPosition = diffBottom > myWindow.getHeight() + 10
|
verticalPosition = diffBottom > myWindow.getHeight() + 20
|
||||||
? RelativeLayout.ALIGN_PARENT_TOP : RelativeLayout.CENTER_VERTICAL;
|
? RelativeLayout.ALIGN_PARENT_TOP : RelativeLayout.CENTER_VERTICAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,20 @@ package org.geometerplus.android.fbreader;
|
||||||
import org.geometerplus.fbreader.fbreader.FBReaderApp;
|
import org.geometerplus.fbreader.fbreader.FBReaderApp;
|
||||||
import org.geometerplus.fbreader.fbreader.FBView;
|
import org.geometerplus.fbreader.fbreader.FBView;
|
||||||
|
|
||||||
public class SelectionDictionaryAction extends FBAndroidAction {
|
public class SelectionTranslateAction extends FBAndroidAction {
|
||||||
SelectionDictionaryAction(FBReader baseActivity, FBReaderApp fbreader) {
|
SelectionTranslateAction(FBReader baseActivity, FBReaderApp fbreader) {
|
||||||
super(baseActivity, fbreader);
|
super(baseActivity, fbreader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
final FBView fbview = Reader.getTextView();
|
final FBView fbview = Reader.getTextView();
|
||||||
final int selectionStartY = fbview.getSelectionStartY(), selectionEndY = fbview.getSelectionEndY();
|
DictionaryUtil.openTextInDictionary(
|
||||||
final String text = fbview.getSelectedText();
|
BaseActivity,
|
||||||
Reader.getTextView().clearSelection();
|
fbview.getSelectedText(),
|
||||||
DictionaryUtil.openTextInDictionary(BaseActivity, text, selectionStartY, selectionEndY);
|
fbview.getCountOfSelectedWords() == 1,
|
||||||
|
fbview.getSelectionStartY(),
|
||||||
|
fbview.getSelectionEndY()
|
||||||
|
);
|
||||||
|
fbview.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -32,10 +32,10 @@ import org.geometerplus.android.fbreader.PackageInfo;
|
||||||
class DictionaryPreference extends ZLStringListPreference {
|
class DictionaryPreference extends ZLStringListPreference {
|
||||||
private final ZLStringOption myOption;
|
private final ZLStringOption myOption;
|
||||||
|
|
||||||
DictionaryPreference(Context context, ZLResource resource, String resourceKey) {
|
DictionaryPreference(Context context, ZLResource resource, String resourceKey, ZLStringOption dictionaryOption) {
|
||||||
super(context, resource, resourceKey);
|
super(context, resource, resourceKey);
|
||||||
|
|
||||||
myOption = DictionaryUtil.dictionaryOption();
|
myOption = dictionaryOption;
|
||||||
final List<PackageInfo> infos = DictionaryUtil.dictionaryInfos(context);
|
final List<PackageInfo> infos = DictionaryUtil.dictionaryInfos(context);
|
||||||
|
|
||||||
final String[] values = new String[infos.size()];
|
final String[] values = new String[infos.size()];
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.geometerplus.fbreader.fbreader.*;
|
||||||
import org.geometerplus.fbreader.Paths;
|
import org.geometerplus.fbreader.Paths;
|
||||||
import org.geometerplus.fbreader.bookmodel.FBTextKind;
|
import org.geometerplus.fbreader.bookmodel.FBTextKind;
|
||||||
|
|
||||||
|
import org.geometerplus.android.fbreader.DictionaryUtil;
|
||||||
|
|
||||||
public class PreferenceActivity extends ZLPreferenceActivity {
|
public class PreferenceActivity extends ZLPreferenceActivity {
|
||||||
public PreferenceActivity() {
|
public PreferenceActivity() {
|
||||||
super("Preferences");
|
super("Preferences");
|
||||||
|
@ -375,7 +377,14 @@ public class PreferenceActivity extends ZLPreferenceActivity {
|
||||||
dictionaryScreen.addPreference(new DictionaryPreference(
|
dictionaryScreen.addPreference(new DictionaryPreference(
|
||||||
this,
|
this,
|
||||||
dictionaryScreen.Resource,
|
dictionaryScreen.Resource,
|
||||||
"dictionary"
|
"dictionary",
|
||||||
|
DictionaryUtil.singleWordTranslatorOption()
|
||||||
|
));
|
||||||
|
dictionaryScreen.addPreference(new DictionaryPreference(
|
||||||
|
this,
|
||||||
|
dictionaryScreen.Resource,
|
||||||
|
"translator",
|
||||||
|
DictionaryUtil.multiWordTranslatorOption()
|
||||||
));
|
));
|
||||||
dictionaryScreen.addPreference(new ZLBooleanPreference(
|
dictionaryScreen.addPreference(new ZLBooleanPreference(
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -63,6 +63,6 @@ public interface ActionCode {
|
||||||
String SELECTION_CLEAR = "selectionClear";
|
String SELECTION_CLEAR = "selectionClear";
|
||||||
String SELECTION_COPY_TO_CLIPBOARD = "selectionCopyToClipboard";
|
String SELECTION_COPY_TO_CLIPBOARD = "selectionCopyToClipboard";
|
||||||
String SELECTION_SHARE = "selectionShare";
|
String SELECTION_SHARE = "selectionShare";
|
||||||
String SELECTION_OPEN_IN_DICTIONARY = "selectionOpenInDictionary";
|
String SELECTION_TRANSLATE = "selectionTranslate";
|
||||||
String SELECTION_ADD_BOOKMARK = "selectionAddBookmark";
|
String SELECTION_BOOKMARK = "selectionBookmark";
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ public final class FBView extends ZLTextView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFlickScrollingEnabled()) {
|
if (isFlickScrollingEnabled()) {
|
||||||
myReader.getViewWidget().startAutoScrolling(
|
myReader.getViewWidget().startAnimatedScrolling(
|
||||||
x, y, ScrollingPreferences.Instance().AnimationSpeedOption.getValue()
|
x, y, ScrollingPreferences.Instance().AnimationSpeedOption.getValue()
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
|
@ -601,17 +601,27 @@ public final class FBView extends ZLTextView {
|
||||||
@Override
|
@Override
|
||||||
protected void releaseSelectionCursor() {
|
protected void releaseSelectionCursor() {
|
||||||
super.releaseSelectionCursor();
|
super.releaseSelectionCursor();
|
||||||
myReader.doAction(ActionCode.SELECTION_SHOW_PANEL);
|
if (getCountOfSelectedWords() > 0) {
|
||||||
|
myReader.doAction(ActionCode.SELECTION_SHOW_PANEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSelectedText() {
|
public String getSelectedText() {
|
||||||
final TextBuilderTraverser traverser = new TextBuilderTraverser(this);
|
final TextBuildTraverser traverser = new TextBuildTraverser(this);
|
||||||
if (!isSelectionEmpty()) {
|
if (!isSelectionEmpty()) {
|
||||||
traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition());
|
traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition());
|
||||||
}
|
}
|
||||||
return traverser.getText();
|
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;
|
public static final int SCROLLBAR_SHOW_AS_FOOTER = 3;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,10 +21,10 @@ package org.geometerplus.fbreader.fbreader;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.text.view.*;
|
import org.geometerplus.zlibrary.text.view.*;
|
||||||
|
|
||||||
class TextBuilderTraverser extends ZLTextTraverser {
|
class TextBuildTraverser extends ZLTextTraverser {
|
||||||
protected final StringBuilder myBuffer = new StringBuilder();
|
protected final StringBuilder myBuffer = new StringBuilder();
|
||||||
|
|
||||||
TextBuilderTraverser(ZLTextView view) {
|
TextBuildTraverser(ZLTextView view) {
|
||||||
super(view);
|
super(view);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class TurnPageAction extends FBAction {
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
|
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
|
||||||
Reader.getViewWidget().startAutoScrolling(
|
Reader.getViewWidget().startAnimatedScrolling(
|
||||||
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
||||||
preferences.HorizontalOption.getValue()
|
preferences.HorizontalOption.getValue()
|
||||||
? FBView.Direction.rightToLeft : FBView.Direction.up,
|
? FBView.Direction.rightToLeft : FBView.Direction.up,
|
||||||
|
@ -49,7 +49,7 @@ class TurnPageAction extends FBAction {
|
||||||
|
|
||||||
public void runWithCoordinates(int x, int y) {
|
public void runWithCoordinates(int x, int y) {
|
||||||
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
|
final ScrollingPreferences preferences = ScrollingPreferences.Instance();
|
||||||
Reader.getViewWidget().startAutoScrolling(
|
Reader.getViewWidget().startAnimatedScrolling(
|
||||||
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
myForward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
||||||
x, y,
|
x, y,
|
||||||
preferences.HorizontalOption.getValue()
|
preferences.HorizontalOption.getValue()
|
||||||
|
|
|
@ -39,7 +39,7 @@ class VolumeKeyTurnPageAction extends FBAction {
|
||||||
forward = !forward;
|
forward = !forward;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reader.getViewWidget().startAutoScrolling(
|
Reader.getViewWidget().startAnimatedScrolling(
|
||||||
forward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
forward ? FBView.PageIndex.next : FBView.PageIndex.previous,
|
||||||
preferences.HorizontalOption.getValue()
|
preferences.HorizontalOption.getValue()
|
||||||
? FBView.Direction.rightToLeft : FBView.Direction.up,
|
? FBView.Direction.rightToLeft : FBView.Direction.up,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ public interface ZLViewWidget {
|
||||||
|
|
||||||
void startManualScrolling(int x, int y, ZLView.Direction direction);
|
void startManualScrolling(int x, int y, ZLView.Direction direction);
|
||||||
void scrollManuallyTo(int x, int y);
|
void scrollManuallyTo(int x, int y);
|
||||||
void startAutoScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed);
|
void startAnimatedScrolling(ZLView.PageIndex pageIndex, int x, int y, ZLView.Direction direction, int speed);
|
||||||
void startAutoScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed);
|
void startAnimatedScrolling(ZLView.PageIndex pageIndex, ZLView.Direction direction, int speed);
|
||||||
void startAutoScrolling(int x, int y, int speed);
|
void startAnimatedScrolling(int x, int y, int speed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
|
||||||
final ZLTextStyle Style;
|
final ZLTextStyle Style;
|
||||||
final ZLTextElement Element;
|
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);
|
super(paragraphIndex, elementIndex, charIndex);
|
||||||
|
|
||||||
XStart = xStart;
|
XStart = xStart;
|
||||||
|
@ -40,6 +42,8 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
|
||||||
YEnd = yEnd;
|
YEnd = yEnd;
|
||||||
|
|
||||||
Length = length;
|
Length = length;
|
||||||
|
myIsLastInElement = lastInElement;
|
||||||
|
|
||||||
AddHyphenationSign = addHyphenationSign;
|
AddHyphenationSign = addHyphenationSign;
|
||||||
ChangeStyle = changeStyle;
|
ChangeStyle = changeStyle;
|
||||||
Style = style;
|
Style = style;
|
||||||
|
@ -55,7 +59,6 @@ final class ZLTextElementArea extends ZLTextFixedPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isLastInElement() {
|
boolean isLastInElement() {
|
||||||
// TODO: support multi-part (> 2 part) words
|
return myIsLastInElement;
|
||||||
return !(Element instanceof ZLTextWord) || CharIndex > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,31 @@ package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
|
final class ZLTextElementAreaVector {
|
||||||
private static final long serialVersionUID = -7880472347947563506L;
|
private final List<ZLTextElementArea> myAreas =
|
||||||
|
Collections.synchronizedList(new ArrayList<ZLTextElementArea>());
|
||||||
private final ArrayList<ZLTextRegion> myElementRegions = new ArrayList<ZLTextRegion>();
|
private final List<ZLTextRegion> myElementRegions =
|
||||||
|
Collections.synchronizedList(new ArrayList<ZLTextRegion>());
|
||||||
private ZLTextRegion myCurrentElementRegion;
|
private ZLTextRegion myCurrentElementRegion;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
myElementRegions.clear();
|
myElementRegions.clear();
|
||||||
myCurrentElementRegion = null;
|
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) {
|
public boolean add(ZLTextElementArea area) {
|
||||||
if (myCurrentElementRegion != null
|
if (myCurrentElementRegion != null
|
||||||
&& myCurrentElementRegion.getSoul().accepts(area)) {
|
&& myCurrentElementRegion.getSoul().accepts(area)) {
|
||||||
|
@ -50,13 +61,13 @@ final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
|
||||||
soul = new ZLTextWordRegionSoul(area, (ZLTextWord)area.Element);
|
soul = new ZLTextWordRegionSoul(area, (ZLTextWord)area.Element);
|
||||||
}
|
}
|
||||||
if (soul != null) {
|
if (soul != null) {
|
||||||
myCurrentElementRegion = new ZLTextRegion(soul, this, size());
|
myCurrentElementRegion = new ZLTextRegion(soul, myAreas, size());
|
||||||
myElementRegions.add(myCurrentElementRegion);
|
myElementRegions.add(myCurrentElementRegion);
|
||||||
} else {
|
} else {
|
||||||
myCurrentElementRegion = null;
|
myCurrentElementRegion = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.add(area);
|
return myAreas.add(area);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextElementArea binarySearch(int x, int y) {
|
ZLTextElementArea binarySearch(int x, int y) {
|
||||||
|
@ -80,17 +91,121 @@ final class ZLTextElementAreaVector extends ArrayList<ZLTextElementArea> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ZLTextRegion> elementRegions() {
|
|
||||||
return Collections.unmodifiableList(myElementRegions);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZLTextRegion getRegion(ZLTextRegion.Soul soul) {
|
ZLTextRegion getRegion(ZLTextRegion.Soul soul) {
|
||||||
if (soul == null) {
|
if (soul == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (ZLTextRegion region : myElementRegions) {
|
synchronized (myElementRegions) {
|
||||||
if (soul.equals(region.getSoul())) {
|
for (ZLTextRegion region : myElementRegions) {
|
||||||
return region;
|
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;
|
return null;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
||||||
class ZLTextHorizontalConvexHull {
|
class ZLTextHorizontalConvexHull {
|
||||||
private final LinkedList<Rectangle> myRectangles = new LinkedList<Rectangle>();
|
private final LinkedList<Rectangle> myRectangles = new LinkedList<Rectangle>();
|
||||||
|
|
||||||
ZLTextHorizontalConvexHull(List<ZLTextElementArea> textAreas) {
|
ZLTextHorizontalConvexHull(ZLTextElementArea[] textAreas) {
|
||||||
for (ZLTextElementArea area : textAreas) {
|
for (ZLTextElementArea area : textAreas) {
|
||||||
addArea(area);
|
addArea(area);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,31 @@
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
public class ZLTextHyperlink {
|
public class ZLTextHyperlink {
|
||||||
public final byte Type;
|
public final byte Type;
|
||||||
public final String Id;
|
public final String Id;
|
||||||
|
|
||||||
|
private List<Integer> myElementIndexes;
|
||||||
|
|
||||||
public static final ZLTextHyperlink NO_LINK = new ZLTextHyperlink((byte)0, null);
|
public static final ZLTextHyperlink NO_LINK = new ZLTextHyperlink((byte)0, null);
|
||||||
|
|
||||||
ZLTextHyperlink(byte type, String id) {
|
ZLTextHyperlink(byte type, String id) {
|
||||||
Type = type;
|
Type = type;
|
||||||
Id = id;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,27 @@
|
||||||
|
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ZLTextHyperlinkRegionSoul extends ZLTextRegion.Soul {
|
public class ZLTextHyperlinkRegionSoul extends ZLTextRegion.Soul {
|
||||||
public final ZLTextHyperlink Hyperlink;
|
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) {
|
ZLTextHyperlinkRegionSoul(ZLTextPosition position, ZLTextHyperlink hyperlink) {
|
||||||
// TODO: fix this call
|
super(
|
||||||
super(position.getParagraphIndex(), position.getElementIndex(), position.getElementIndex());
|
position.getParagraphIndex(),
|
||||||
|
startElementIndex(hyperlink, position.getElementIndex()),
|
||||||
|
endElementIndex(hyperlink, position.getElementIndex())
|
||||||
|
);
|
||||||
Hyperlink = hyperlink;
|
Hyperlink = hyperlink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public final class ZLTextParagraphCursor {
|
||||||
private int myFirstMark;
|
private int myFirstMark;
|
||||||
private int myLastMark;
|
private int myLastMark;
|
||||||
private final List<ZLTextMark> myMarks;
|
private final List<ZLTextMark> myMarks;
|
||||||
|
|
||||||
private Processor(ZLTextParagraph paragraph, LineBreaker lineBreaker, List<ZLTextMark> marks, int paragraphIndex, ArrayList<ZLTextElement> elements) {
|
private Processor(ZLTextParagraph paragraph, LineBreaker lineBreaker, List<ZLTextMark> marks, int paragraphIndex, ArrayList<ZLTextElement> elements) {
|
||||||
myParagraph = paragraph;
|
myParagraph = paragraph;
|
||||||
myLineBreaker = lineBreaker;
|
myLineBreaker = lineBreaker;
|
||||||
|
@ -54,20 +54,33 @@ public final class ZLTextParagraphCursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill() {
|
void fill() {
|
||||||
|
int hyperlinkDepth = 0;
|
||||||
|
ZLTextHyperlink hyperlink = null;
|
||||||
|
|
||||||
final ArrayList<ZLTextElement> elements = myElements;
|
final ArrayList<ZLTextElement> elements = myElements;
|
||||||
for (ZLTextParagraph.EntryIterator it = myParagraph.iterator(); it.hasNext(); ) {
|
for (ZLTextParagraph.EntryIterator it = myParagraph.iterator(); it.hasNext(); ) {
|
||||||
it.next();
|
it.next();
|
||||||
switch (it.getType()) {
|
switch (it.getType()) {
|
||||||
case ZLTextParagraph.Entry.TEXT:
|
case ZLTextParagraph.Entry.TEXT:
|
||||||
processTextEntry(it.getTextData(), it.getTextOffset(), it.getTextLength());
|
processTextEntry(it.getTextData(), it.getTextOffset(), it.getTextLength(), hyperlink);
|
||||||
break;
|
break;
|
||||||
case ZLTextParagraph.Entry.CONTROL:
|
case ZLTextParagraph.Entry.CONTROL:
|
||||||
|
if (hyperlink != null) {
|
||||||
|
hyperlinkDepth += it.getControlIsStart() ? 1 : -1;
|
||||||
|
if (hyperlinkDepth == 0) {
|
||||||
|
hyperlink = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (it.getControlIsStart()) {
|
if (it.getControlIsStart()) {
|
||||||
final byte hyperlinkType = it.getHyperlinkType();
|
final byte hyperlinkType = it.getHyperlinkType();
|
||||||
if (hyperlinkType != 0) {
|
if (hyperlinkType != 0) {
|
||||||
elements.add(new ZLTextHyperlinkControlElement(
|
final ZLTextHyperlinkControlElement control =
|
||||||
it.getControlKind(), hyperlinkType, it.getHyperlinkId()
|
new ZLTextHyperlinkControlElement(
|
||||||
));
|
it.getControlKind(), hyperlinkType, it.getHyperlinkId()
|
||||||
|
);
|
||||||
|
elements.add(control);
|
||||||
|
hyperlink = control.Hyperlink;
|
||||||
|
hyperlinkDepth = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +92,9 @@ public final class ZLTextParagraphCursor {
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
ZLImageData data = ZLImageManager.Instance().getImageData(image);
|
ZLImageData data = ZLImageManager.Instance().getImageData(image);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
|
if (hyperlink != null) {
|
||||||
|
hyperlink.addElementIndex(elements.size());
|
||||||
|
}
|
||||||
elements.add(new ZLTextImageElement(imageEntry.Id, data, image.getURI()));
|
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 byte[] ourBreaks = new byte[1024];
|
||||||
private static final int NO_SPACE = 0;
|
private static final int NO_SPACE = 0;
|
||||||
private static final int SPACE = 1;
|
private static final int SPACE = 1;
|
||||||
//private static final int NON_BREAKABLE_SPACE = 2;
|
//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 (length != 0) {
|
||||||
if (ourBreaks.length < length) {
|
if (ourBreaks.length < length) {
|
||||||
ourBreaks = new byte[length];
|
ourBreaks = new byte[length];
|
||||||
|
@ -116,7 +132,7 @@ public final class ZLTextParagraphCursor {
|
||||||
ch = data[offset + index];
|
ch = data[offset + index];
|
||||||
if (Character.isSpace(ch)) {
|
if (Character.isSpace(ch)) {
|
||||||
if (index > 0 && spaceState == NO_SPACE) {
|
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;
|
spaceState = SPACE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,7 +150,7 @@ public final class ZLTextParagraphCursor {
|
||||||
breaks[index - 1] != LineBreaker.NOBREAK &&
|
breaks[index - 1] != LineBreaker.NOBREAK &&
|
||||||
previousChar != '-' &&
|
previousChar != '-' &&
|
||||||
index != wordStart) {
|
index != wordStart) {
|
||||||
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart);
|
addWord(data, offset + wordStart, index - wordStart, myOffset + wordStart, hyperlink);
|
||||||
wordStart = index;
|
wordStart = index;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -149,14 +165,14 @@ public final class ZLTextParagraphCursor {
|
||||||
//case NON_BREAKABLE_SPACE:
|
//case NON_BREAKABLE_SPACE:
|
||||||
//break;
|
//break;
|
||||||
case NO_SPACE:
|
case NO_SPACE:
|
||||||
addWord(data, offset + wordStart, length - wordStart, myOffset + wordStart);
|
addWord(data, offset + wordStart, length - wordStart, myOffset + wordStart, hyperlink);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
myOffset += length;
|
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);
|
ZLTextWord word = new ZLTextWord(data, offset, len, paragraphOffset);
|
||||||
for (int i = myFirstMark; i < myLastMark; ++i) {
|
for (int i = myFirstMark; i < myLastMark; ++i) {
|
||||||
final ZLTextMark mark = (ZLTextMark)myMarks.get(i);
|
final ZLTextMark mark = (ZLTextMark)myMarks.get(i);
|
||||||
|
@ -164,10 +180,13 @@ public final class ZLTextParagraphCursor {
|
||||||
word.addMark(mark.Offset - paragraphOffset, mark.Length);
|
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 int Index;
|
||||||
public final ZLTextModel Model;
|
public final ZLTextModel Model;
|
||||||
private final ArrayList<ZLTextElement> myElements = new ArrayList<ZLTextElement>();
|
private final ArrayList<ZLTextElement> myElements = new ArrayList<ZLTextElement>();
|
||||||
|
@ -177,7 +196,7 @@ public final class ZLTextParagraphCursor {
|
||||||
Index = Math.min(index, Model.getParagraphsNumber() - 1);
|
Index = Math.min(index, Model.getParagraphsNumber() - 1);
|
||||||
fill();
|
fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZLTextParagraphCursor cursor(ZLTextModel model, int index) {
|
static ZLTextParagraphCursor cursor(ZLTextModel model, int index) {
|
||||||
ZLTextParagraphCursor result = ZLTextParagraphCursorCache.get(model, index);
|
ZLTextParagraphCursor result = ZLTextParagraphCursorCache.get(model, index);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
@ -201,7 +220,7 @@ public final class ZLTextParagraphCursor {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
myElements.clear();
|
myElements.clear();
|
||||||
}
|
}
|
||||||
|
@ -213,11 +232,11 @@ public final class ZLTextParagraphCursor {
|
||||||
public boolean isLast() {
|
public boolean isLast() {
|
||||||
return (Index + 1 >= Model.getParagraphsNumber());
|
return (Index + 1 >= Model.getParagraphsNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEndOfSection() {
|
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() {
|
int getParagraphLength() {
|
||||||
return myElements.size();
|
return myElements.size();
|
||||||
}
|
}
|
||||||
|
@ -229,7 +248,7 @@ public final class ZLTextParagraphCursor {
|
||||||
public ZLTextParagraphCursor next() {
|
public ZLTextParagraphCursor next() {
|
||||||
return isLast() ? null : cursor(Model, Index + 1);
|
return isLast() ? null : cursor(Model, Index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextElement getElement(int index) {
|
ZLTextElement getElement(int index) {
|
||||||
try {
|
try {
|
||||||
return myElements.get(index);
|
return myElements.get(index);
|
||||||
|
@ -239,7 +258,7 @@ public final class ZLTextParagraphCursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextParagraph getParagraph() {
|
ZLTextParagraph getParagraph() {
|
||||||
return Model.getParagraph(Index);
|
return Model.getParagraph(Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,7 +23,7 @@ import java.util.*;
|
||||||
|
|
||||||
import org.geometerplus.zlibrary.core.view.ZLPaintContext;
|
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> {
|
public static abstract class Soul implements Comparable<Soul> {
|
||||||
final int ParagraphIndex;
|
final int ParagraphIndex;
|
||||||
final int StartElementIndex;
|
final int StartElementIndex;
|
||||||
|
@ -107,14 +107,16 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Soul mySoul;
|
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 final int myFromIndex;
|
||||||
private int myToIndex;
|
private int myToIndex;
|
||||||
private ZLTextHorizontalConvexHull myHull;
|
private ZLTextHorizontalConvexHull myHull;
|
||||||
|
|
||||||
ZLTextRegion(Soul soul, List<ZLTextElementArea> list, int fromIndex) {
|
ZLTextRegion(Soul soul, List<ZLTextElementArea> list, int fromIndex) {
|
||||||
mySoul = soul;
|
mySoul = soul;
|
||||||
myList = list;
|
myAreaList = list;
|
||||||
myFromIndex = fromIndex;
|
myFromIndex = fromIndex;
|
||||||
myToIndex = fromIndex + 1;
|
myToIndex = fromIndex + 1;
|
||||||
}
|
}
|
||||||
|
@ -128,8 +130,16 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
|
||||||
return mySoul;
|
return mySoul;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ZLTextElementArea> textAreas() {
|
private ZLTextElementArea[] textAreas() {
|
||||||
return myList.subList(myFromIndex, myToIndex);
|
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() {
|
private ZLTextHorizontalConvexHull convexHull() {
|
||||||
if (myHull == null) {
|
if (myHull == null) {
|
||||||
|
@ -139,11 +149,12 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextElementArea getFirstArea() {
|
ZLTextElementArea getFirstArea() {
|
||||||
return myList.get(myFromIndex);
|
return textAreas()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextElementArea getLastArea() {
|
ZLTextElementArea getLastArea() {
|
||||||
return myList.get(myToIndex - 1);
|
final ZLTextElementArea[] areas = textAreas();
|
||||||
|
return areas[areas.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTop() {
|
public int getTop() {
|
||||||
|
@ -189,8 +200,8 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
|
||||||
if (!isUnder(other)) {
|
if (!isUnder(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final List<ZLTextElementArea> areas0 = textAreas();
|
final ZLTextElementArea[] areas0 = textAreas();
|
||||||
final List<ZLTextElementArea> areas1 = other.textAreas();
|
final ZLTextElementArea[] areas1 = other.textAreas();
|
||||||
for (ZLTextElementArea i : areas0) {
|
for (ZLTextElementArea i : areas0) {
|
||||||
for (ZLTextElementArea j : areas1) {
|
for (ZLTextElementArea j : areas1) {
|
||||||
if (i.XStart <= j.XEnd && j.XStart <= i.XEnd) {
|
if (i.XStart <= j.XEnd && j.XStart <= i.XEnd) {
|
||||||
|
@ -204,16 +215,4 @@ public final class ZLTextRegion /*implements Comparable<ZLTextRegion>*/ {
|
||||||
boolean isExactlyOver(ZLTextRegion other) {
|
boolean isExactlyOver(ZLTextRegion other) {
|
||||||
return other == null || other.isExactlyUnder(this);
|
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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,27 @@
|
||||||
package org.geometerplus.zlibrary.text.view;
|
package org.geometerplus.zlibrary.text.view;
|
||||||
|
|
||||||
public class ZLTextSelection {
|
public class ZLTextSelection {
|
||||||
|
static class Point {
|
||||||
|
int X;
|
||||||
|
int Y;
|
||||||
|
|
||||||
|
Point(int x, int y) {
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final ZLTextView myView;
|
private final ZLTextView myView;
|
||||||
|
|
||||||
private ZLTextRegion.Soul myLeftMostRegionSoul;
|
private ZLTextRegion.Soul myLeftMostRegionSoul;
|
||||||
private ZLTextRegion.Soul myRightMostRegionSoul;
|
private ZLTextRegion.Soul myRightMostRegionSoul;
|
||||||
|
|
||||||
|
private ZLTextSelectionCursor myCursorInMovement = ZLTextSelectionCursor.None;
|
||||||
|
private final Point myCursorInMovementPoint = new Point(-1, -1);
|
||||||
|
|
||||||
private Scroller myScroller;
|
private Scroller myScroller;
|
||||||
|
|
||||||
|
|
||||||
ZLTextSelection(ZLTextView view) {
|
ZLTextSelection(ZLTextView view) {
|
||||||
myView = view;
|
myView = view;
|
||||||
}
|
}
|
||||||
|
@ -43,9 +57,24 @@ public class ZLTextSelection {
|
||||||
stop();
|
stop();
|
||||||
myLeftMostRegionSoul = null;
|
myLeftMostRegionSoul = null;
|
||||||
myRightMostRegionSoul = null;
|
myRightMostRegionSoul = null;
|
||||||
|
myCursorInMovement = ZLTextSelectionCursor.None;
|
||||||
return true;
|
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) {
|
boolean start(int x, int y) {
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
@ -61,35 +90,36 @@ public class ZLTextSelection {
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
|
myCursorInMovement = ZLTextSelectionCursor.None;
|
||||||
if (myScroller != null) {
|
if (myScroller != null) {
|
||||||
myScroller.stop();
|
myScroller.stop();
|
||||||
myScroller = null;
|
myScroller = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextSelectionCursor expandTo(int x, int y, ZLTextSelectionCursor cursorToMove) {
|
void expandTo(int x, int y) {
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return cursorToMove;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
final ZLTextElementAreaVector vector = myView.myCurrentPage.TextElementMap;
|
||||||
if (y < 10) {
|
if (!vector.isEmpty() && y < vector.get(0).YStart) {
|
||||||
if (myScroller != null && myScroller.scrollsForward()) {
|
if (myScroller != null && myScroller.scrollsForward()) {
|
||||||
myScroller.stop();
|
myScroller.stop();
|
||||||
myScroller = null;
|
myScroller = null;
|
||||||
}
|
}
|
||||||
if (myScroller == null) {
|
if (myScroller == null) {
|
||||||
myScroller = new Scroller(false, x, y);
|
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()) {
|
if (myScroller != null && !myScroller.scrollsForward()) {
|
||||||
myScroller.stop();
|
myScroller.stop();
|
||||||
myScroller = null;
|
myScroller = null;
|
||||||
}
|
}
|
||||||
if (myScroller == null) {
|
if (myScroller == null) {
|
||||||
myScroller = new Scroller(true, x, y);
|
myScroller = new Scroller(true, x, y);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (myScroller != null) {
|
if (myScroller != null) {
|
||||||
|
@ -101,34 +131,45 @@ public class ZLTextSelection {
|
||||||
if (myScroller != null) {
|
if (myScroller != null) {
|
||||||
myScroller.setXY(x, y);
|
myScroller.setXY(x, y);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
ZLTextRegion region = myView.findRegion(x, y, ZLTextView.MAX_SELECTION_DISTANCE, ZLTextRegion.AnyRegionFilter);
|
ZLTextRegion region = myView.findRegion(x, y, ZLTextView.MAX_SELECTION_DISTANCE, ZLTextRegion.AnyRegionFilter);
|
||||||
if (region == null && myScroller != null) {
|
if (region == null && myScroller != null) {
|
||||||
region = myView.findRegion(x, y, ZLTextRegion.AnyRegionFilter);
|
region = myView.findRegion(x, y, ZLTextRegion.AnyRegionFilter);
|
||||||
}
|
}
|
||||||
if (region == null) {
|
if (region == null) {
|
||||||
return cursorToMove;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ZLTextRegion.Soul soul = region.getSoul();
|
final ZLTextRegion.Soul soul = region.getSoul();
|
||||||
if (cursorToMove == ZLTextSelectionCursor.Right) {
|
if (myCursorInMovement == ZLTextSelectionCursor.Right) {
|
||||||
if (myLeftMostRegionSoul.compareTo(soul) <= 0) {
|
if (myLeftMostRegionSoul.compareTo(soul) <= 0) {
|
||||||
myRightMostRegionSoul = soul;
|
myRightMostRegionSoul = soul;
|
||||||
return cursorToMove;
|
|
||||||
} else {
|
} else {
|
||||||
myRightMostRegionSoul = myLeftMostRegionSoul;
|
myRightMostRegionSoul = myLeftMostRegionSoul;
|
||||||
myLeftMostRegionSoul = soul;
|
myLeftMostRegionSoul = soul;
|
||||||
return ZLTextSelectionCursor.Left;
|
myCursorInMovement = ZLTextSelectionCursor.Left;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (myRightMostRegionSoul.compareTo(soul) >= 0) {
|
if (myRightMostRegionSoul.compareTo(soul) >= 0) {
|
||||||
myLeftMostRegionSoul = soul;
|
myLeftMostRegionSoul = soul;
|
||||||
return cursorToMove;
|
|
||||||
} else {
|
} else {
|
||||||
myLeftMostRegionSoul = myRightMostRegionSoul;
|
myLeftMostRegionSoul = myRightMostRegionSoul;
|
||||||
myRightMostRegionSoul = soul;
|
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) {
|
if (region != null) {
|
||||||
return region.getFirstArea();
|
return region.getFirstArea();
|
||||||
}
|
}
|
||||||
if (myRightMostRegionSoul.compareTo(vector.get(0)) >= 0) {
|
if (myLeftMostRegionSoul.compareTo(vector.get(0)) <= 0) {
|
||||||
return vector.get(0);
|
return vector.get(0);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -246,7 +287,7 @@ public class ZLTextSelection {
|
||||||
public void run() {
|
public void run() {
|
||||||
myView.scrollPage(myScrollForward, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
|
myView.scrollPage(myScrollForward, ZLTextView.ScrollingMode.SCROLL_LINES, 1);
|
||||||
myView.preparePaintInfo();
|
myView.preparePaintInfo();
|
||||||
//expandTo(myX, myY, myScrollForward);
|
expandTo(myX, myY);
|
||||||
myView.Application.getViewWidget().reset();
|
myView.Application.getViewWidget().reset();
|
||||||
myView.Application.getViewWidget().repaint();
|
myView.Application.getViewWidget().repaint();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
myNextPage.reset();
|
myNextPage.reset();
|
||||||
myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);
|
myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);
|
||||||
myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;
|
myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;
|
||||||
|
Application.getViewWidget().reset();
|
||||||
}
|
}
|
||||||
break;
|
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) {
|
protected void moveSelectionCursorTo(ZLTextSelectionCursor cursor, int x, int y) {
|
||||||
y -= ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2;
|
y -= ZLTextSelectionCursor.getHeight() / 2 + ZLTextSelectionCursor.getAccent() / 2;
|
||||||
mySelectionCursorInMovement = mySelection.expandTo(x, y, cursor);
|
mySelection.setCursorInMovement(cursor, x, y);
|
||||||
myMovedSelectionCursorPoint.X = x;
|
mySelection.expandTo(x, y);
|
||||||
myMovedSelectionCursorPoint.Y = y;
|
|
||||||
Application.getViewWidget().reset();
|
Application.getViewWidget().reset();
|
||||||
Application.getViewWidget().repaint();
|
Application.getViewWidget().repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releaseSelectionCursor() {
|
protected void releaseSelectionCursor() {
|
||||||
mySelectionCursorInMovement = ZLTextSelectionCursor.None;
|
|
||||||
mySelection.stop();
|
mySelection.stop();
|
||||||
Application.getViewWidget().reset();
|
Application.getViewWidget().reset();
|
||||||
Application.getViewWidget().repaint();
|
Application.getViewWidget().repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ZLTextSelectionCursor getSelectionCursorInMovement() {
|
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) {
|
if (cursor == ZLTextSelectionCursor.None) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor == mySelectionCursorInMovement) {
|
if (cursor == mySelection.getCursorInMovement()) {
|
||||||
return myMovedSelectionCursorPoint;
|
return mySelection.getCursorInMovementPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor == ZLTextSelectionCursor.Left) {
|
if (cursor == ZLTextSelectionCursor.Left) {
|
||||||
|
@ -286,7 +272,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
final ZLTextElementArea selectionStartArea = mySelection.getStartArea(page);
|
final ZLTextElementArea selectionStartArea = mySelection.getStartArea(page);
|
||||||
if (selectionStartArea != null) {
|
if (selectionStartArea != null) {
|
||||||
return new Point(selectionStartArea.XStart, selectionStartArea.YEnd);
|
return new ZLTextSelection.Point(selectionStartArea.XStart, selectionStartArea.YEnd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mySelection.hasAPartAfterPage(page)) {
|
if (mySelection.hasAPartAfterPage(page)) {
|
||||||
|
@ -294,13 +280,13 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
final ZLTextElementArea selectionEndArea = mySelection.getEndArea(page);
|
final ZLTextElementArea selectionEndArea = mySelection.getEndArea(page);
|
||||||
if (selectionEndArea != null) {
|
if (selectionEndArea != null) {
|
||||||
return new Point(selectionEndArea.XEnd, selectionEndArea.YEnd);
|
return new ZLTextSelection.Point(selectionEndArea.XEnd, selectionEndArea.YEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int distanceToCursor(int x, int y, Point cursorPoint) {
|
private int distanceToCursor(int x, int y, ZLTextSelection.Point cursorPoint) {
|
||||||
if (cursorPoint == null) {
|
if (cursorPoint == null) {
|
||||||
return Integer.MAX_VALUE;
|
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) {
|
if (pt == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -999,7 +985,11 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
if (getTextStyle().isUnderline()) {
|
if (getTextStyle().isUnderline()) {
|
||||||
spaceElement = new ZLTextElementArea(
|
spaceElement = new ZLTextElementArea(
|
||||||
paragraphIndex, wordIndex, 0,
|
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 {
|
} else {
|
||||||
spaceElement = null;
|
spaceElement = null;
|
||||||
|
@ -1017,8 +1007,14 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
page.TextElementMap.add(spaceElement);
|
page.TextElementMap.add(spaceElement);
|
||||||
spaceElement = null;
|
spaceElement = null;
|
||||||
}
|
}
|
||||||
page.TextElementMap.add(new ZLTextElementArea(paragraphIndex, wordIndex, charIndex,
|
page.TextElementMap.add(new ZLTextElementArea(
|
||||||
length - charIndex, false, changeStyle, getTextStyle(), element, x, x + width - 1, y - height + 1, y + descent));
|
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;
|
changeStyle = false;
|
||||||
wordOccurred = true;
|
wordOccurred = true;
|
||||||
} else if (element instanceof ZLTextControlElement) {
|
} else if (element instanceof ZLTextControlElement) {
|
||||||
|
@ -1039,7 +1035,9 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
page.TextElementMap.add(
|
page.TextElementMap.add(
|
||||||
new ZLTextElementArea(
|
new ZLTextElementArea(
|
||||||
paragraphIndex, wordIndex, 0,
|
paragraphIndex, wordIndex, 0,
|
||||||
len, addHyphenationSign,
|
len,
|
||||||
|
false, // is last in element
|
||||||
|
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
|
||||||
)
|
)
|
||||||
|
@ -1372,18 +1370,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ZLTextRegion findRegion(int x, int y, int maxDistance, ZLTextRegion.Filter filter) {
|
protected ZLTextRegion findRegion(int x, int y, int maxDistance, ZLTextRegion.Filter filter) {
|
||||||
ZLTextRegion bestRegion = null;
|
return myCurrentPage.TextElementMap.findRegion(x, y, maxDistance, filter);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void selectRegion(ZLTextRegion region) {
|
protected void selectRegion(ZLTextRegion region) {
|
||||||
|
@ -1405,8 +1392,6 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearSelection() {
|
public void clearSelection() {
|
||||||
mySelectionCursorInMovement = ZLTextSelectionCursor.None;
|
|
||||||
mySelection.stop();
|
|
||||||
if (mySelection.clear()) {
|
if (mySelection.clear()) {
|
||||||
Application.getViewWidget().reset();
|
Application.getViewWidget().reset();
|
||||||
Application.getViewWidget().repaint();
|
Application.getViewWidget().repaint();
|
||||||
|
@ -1463,92 +1448,7 @@ public abstract class ZLTextView extends ZLTextViewBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ZLTextRegion nextRegion(Direction direction, ZLTextRegion.Filter filter) {
|
protected ZLTextRegion nextRegion(Direction direction, ZLTextRegion.Filter filter) {
|
||||||
final List<ZLTextRegion> elementRegions = myCurrentPage.TextElementMap.elementRegions();
|
return myCurrentPage.TextElementMap.nextRegion(getSelectedRegion(), direction, filter);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -91,7 +91,8 @@ abstract class ZLTextViewBase extends ZLView {
|
||||||
|
|
||||||
void applyControl(ZLTextControlElement control) {
|
void applyControl(ZLTextControlElement control) {
|
||||||
if (control.IsStart) {
|
if (control.IsStart) {
|
||||||
ZLTextStyleDecoration decoration = ZLTextStyleCollection.Instance().getDecoration(control.Kind);
|
final ZLTextStyleDecoration decoration =
|
||||||
|
ZLTextStyleCollection.Instance().getDecoration(control.Kind);
|
||||||
if (control instanceof ZLTextHyperlinkControlElement) {
|
if (control instanceof ZLTextHyperlinkControlElement) {
|
||||||
setTextStyle(decoration.createDecoratedStyle(myTextStyle, ((ZLTextHyperlinkControlElement)control).Hyperlink));
|
setTextStyle(decoration.createDecoratedStyle(myTextStyle, ((ZLTextHyperlinkControlElement)control).Hyperlink));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -30,8 +30,8 @@ abstract class AnimationProvider {
|
||||||
static enum Mode {
|
static enum Mode {
|
||||||
NoScrolling(false),
|
NoScrolling(false),
|
||||||
ManualScrolling(false),
|
ManualScrolling(false),
|
||||||
AutoScrollingForward(true),
|
AnimatedScrollingForward(true),
|
||||||
AutoScrollingBackward(true);
|
AnimatedScrollingBackward(true);
|
||||||
|
|
||||||
final boolean Auto;
|
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) {
|
if (myMode != Mode.ManualScrolling) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ abstract class AnimationProvider {
|
||||||
(myHeight > myWidth ? myHeight / 4 : myHeight / 3);
|
(myHeight > myWidth ? myHeight / 4 : myHeight / 3);
|
||||||
boolean forward = Math.abs(diff) > minDiff;
|
boolean forward = Math.abs(diff) > minDiff;
|
||||||
|
|
||||||
myMode = forward ? Mode.AutoScrollingForward : Mode.AutoScrollingBackward;
|
myMode = forward ? Mode.AnimatedScrollingForward : Mode.AnimatedScrollingBackward;
|
||||||
|
|
||||||
float velocity = 15;
|
float velocity = 15;
|
||||||
if (myDrawInfos.size() > 1) {
|
if (myDrawInfos.size() > 1) {
|
||||||
|
@ -136,16 +136,16 @@ abstract class AnimationProvider {
|
||||||
break;
|
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) {
|
if (myMode.Auto) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
terminate();
|
terminate();
|
||||||
myMode = Mode.AutoScrollingForward;
|
myMode = Mode.AnimatedScrollingForward;
|
||||||
|
|
||||||
switch (myDirection) {
|
switch (myDirection) {
|
||||||
case up:
|
case up:
|
||||||
|
@ -157,12 +157,12 @@ abstract class AnimationProvider {
|
||||||
mySpeed = pageIndex == ZLView.PageIndex.next ? 15 : -15;
|
mySpeed = pageIndex == ZLView.PageIndex.next ? 15 : -15;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
setupAutoScrollingStart(x, y);
|
setupAnimatedScrollingStart(x, y);
|
||||||
startAutoScrollingInternal(speed);
|
startAnimatedScrollingInternal(speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void startAutoScrollingInternal(int speed);
|
protected abstract void startAnimatedScrollingInternal(int speed);
|
||||||
protected abstract void setupAutoScrollingStart(Integer x, Integer y);
|
protected abstract void setupAnimatedScrollingStart(Integer x, Integer y);
|
||||||
|
|
||||||
boolean inProgress() {
|
boolean inProgress() {
|
||||||
return myMode != Mode.NoScrolling;
|
return myMode != Mode.NoScrolling;
|
||||||
|
|
|
@ -199,14 +199,14 @@ class CurlAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startAutoScrollingInternal(int speed) {
|
protected void startAnimatedScrollingInternal(int speed) {
|
||||||
mySpeedFactor = (float)Math.pow(2.0, 0.25 * speed);
|
mySpeedFactor = (float)Math.pow(2.0, 0.25 * speed);
|
||||||
mySpeed *= 1.5;
|
mySpeed *= 1.5;
|
||||||
doStep();
|
doStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupAutoScrollingStart(Integer x, Integer y) {
|
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
|
||||||
if (x == null || y == null) {
|
if (x == null || y == null) {
|
||||||
if (myDirection.IsHorizontal) {
|
if (myDirection.IsHorizontal) {
|
||||||
x = mySpeed < 0 ? myWidth - 3 : 3;
|
x = mySpeed < 0 ? myWidth - 3 : 3;
|
||||||
|
@ -245,7 +245,7 @@ class CurlAnimationProvider extends AnimationProvider {
|
||||||
final int cornerY = myStartY > myHeight / 2 ? myHeight : 0;
|
final int cornerY = myStartY > myHeight / 2 ? myHeight : 0;
|
||||||
|
|
||||||
final int boundX, boundY;
|
final int boundX, boundY;
|
||||||
if (getMode() == Mode.AutoScrollingForward) {
|
if (getMode() == Mode.AnimatedScrollingForward) {
|
||||||
boundX = cornerX == 0 ? 2 * myWidth : -myWidth;
|
boundX = cornerX == 0 ? 2 * myWidth : -myWidth;
|
||||||
boundY = cornerY == 0 ? 2 * myHeight : -myHeight;
|
boundY = cornerY == 0 ? 2 * myHeight : -myHeight;
|
||||||
} else {
|
} else {
|
||||||
|
@ -268,7 +268,7 @@ class CurlAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean xSpeedIsPositive, ySpeedIsPositive;
|
final boolean xSpeedIsPositive, ySpeedIsPositive;
|
||||||
if (getMode() == Mode.AutoScrollingForward) {
|
if (getMode() == Mode.AnimatedScrollingForward) {
|
||||||
xSpeedIsPositive = cornerX == 0;
|
xSpeedIsPositive = cornerX == 0;
|
||||||
ySpeedIsPositive = cornerY == 0;
|
ySpeedIsPositive = cornerY == 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -43,7 +43,7 @@ class NoneAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupAutoScrollingStart(Integer x, Integer y) {
|
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
|
||||||
if (myDirection.IsHorizontal) {
|
if (myDirection.IsHorizontal) {
|
||||||
myStartX = mySpeed < 0 ? myWidth : 0;
|
myStartX = mySpeed < 0 ? myWidth : 0;
|
||||||
myEndX = myWidth - myStartX;
|
myEndX = myWidth - myStartX;
|
||||||
|
@ -56,7 +56,7 @@ class NoneAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startAutoScrollingInternal(int speed) {
|
protected void startAnimatedScrollingInternal(int speed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -48,7 +48,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupAutoScrollingStart(Integer x, Integer y) {
|
protected void setupAnimatedScrollingStart(Integer x, Integer y) {
|
||||||
if (x == null || y == null) {
|
if (x == null || y == null) {
|
||||||
if (myDirection.IsHorizontal) {
|
if (myDirection.IsHorizontal) {
|
||||||
x = mySpeed < 0 ? myWidth : 0;
|
x = mySpeed < 0 ? myWidth : 0;
|
||||||
|
@ -63,7 +63,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startAutoScrollingInternal(int speed) {
|
protected void startAnimatedScrollingInternal(int speed) {
|
||||||
mySpeedFactor = (float)Math.pow(1.5, 0.25 * speed);
|
mySpeedFactor = (float)Math.pow(1.5, 0.25 * speed);
|
||||||
doStep();
|
doStep();
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ abstract class SimpleAnimationProvider extends AnimationProvider {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
final int bound;
|
final int bound;
|
||||||
if (getMode() == Mode.AutoScrollingForward) {
|
if (getMode() == Mode.AnimatedScrollingForward) {
|
||||||
bound = myDirection.IsHorizontal ? myWidth : myHeight;
|
bound = myDirection.IsHorizontal ? myWidth : myHeight;
|
||||||
} else {
|
} else {
|
||||||
bound = 0;
|
bound = 0;
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class ZLAndroidWidget extends View implements ZLViewWidget, View.OnLongCl
|
||||||
drawFooter(canvas);
|
drawFooter(canvas);
|
||||||
} else {
|
} else {
|
||||||
switch (oldMode) {
|
switch (oldMode) {
|
||||||
case AutoScrollingForward:
|
case AnimatedScrollingForward:
|
||||||
{
|
{
|
||||||
final ZLView.PageIndex index = animator.getPageToScrollTo();
|
final ZLView.PageIndex index = animator.getPageToScrollTo();
|
||||||
myBitmapManager.shift(index == ZLView.PageIndex.next);
|
myBitmapManager.shift(index == ZLView.PageIndex.next);
|
||||||
|
@ -140,7 +140,7 @@ public class ZLAndroidWidget extends View implements ZLViewWidget, View.OnLongCl
|
||||||
ZLApplication.Instance().onRepaintFinished();
|
ZLApplication.Instance().onRepaintFinished();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AutoScrollingBackward:
|
case AnimatedScrollingBackward:
|
||||||
view.onScrollingFinished(ZLView.PageIndex.current);
|
view.onScrollingFinished(ZLView.PageIndex.current);
|
||||||
break;
|
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();
|
final ZLView view = ZLApplication.Instance().getCurrentView();
|
||||||
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
|
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final AnimationProvider animator = getAnimationProvider();
|
final AnimationProvider animator = getAnimationProvider();
|
||||||
animator.setup(direction, getWidth(), getMainAreaHeight());
|
animator.setup(direction, getWidth(), getMainAreaHeight());
|
||||||
animator.startAutoScrolling(pageIndex, x, y, speed);
|
animator.startAnimatedScrolling(pageIndex, x, y, speed);
|
||||||
if (animator.getMode().Auto) {
|
if (animator.getMode().Auto) {
|
||||||
postInvalidate();
|
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();
|
final ZLView view = ZLApplication.Instance().getCurrentView();
|
||||||
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
|
if (pageIndex == ZLView.PageIndex.current || !view.canScroll(pageIndex)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final AnimationProvider animator = getAnimationProvider();
|
final AnimationProvider animator = getAnimationProvider();
|
||||||
animator.setup(direction, getWidth(), getMainAreaHeight());
|
animator.setup(direction, getWidth(), getMainAreaHeight());
|
||||||
animator.startAutoScrolling(pageIndex, null, null, speed);
|
animator.startAnimatedScrolling(pageIndex, null, null, speed);
|
||||||
if (animator.getMode().Auto) {
|
if (animator.getMode().Auto) {
|
||||||
postInvalidate();
|
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 ZLView view = ZLApplication.Instance().getCurrentView();
|
||||||
final AnimationProvider animator = getAnimationProvider();
|
final AnimationProvider animator = getAnimationProvider();
|
||||||
if (!view.canScroll(animator.getPageToScrollTo(x, y))) {
|
if (!view.canScroll(animator.getPageToScrollTo(x, y))) {
|
||||||
animator.terminate();
|
animator.terminate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
animator.startAutoScrolling(x, y, speed);
|
animator.startAnimatedScrolling(x, y, speed);
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue