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