1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-05 19:42:17 +02:00

smooth scrolling

git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@921 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
Nikolay Pultsin 2009-04-11 09:34:48 +00:00
parent 6596404a5e
commit f7b8cebe42
11 changed files with 477 additions and 266 deletions

View file

@ -48,7 +48,7 @@ public class TOCActivity extends ListActivity {
final FBReader fbreader = (FBReader)ZLApplication.Instance();
final TOCTree root = fbreader.Model.TOCTree;
myAdapter = new TOCAdapter(root);
final ZLTextWordCursor cursor = fbreader.BookTextView.StartCursor;
final ZLTextWordCursor cursor = fbreader.BookTextView.getStartCursor();
int index = cursor.getParagraphCursor().Index;
if (cursor.isEndOfParagraph()) {
++index;

View file

@ -45,7 +45,7 @@ public final class ZLSQLiteConfig extends ZLConfig {
myDeleteGroupStatement = myDatabase.compileStatement("DELETE FROM config WHERE groupName = ?");
}
public void executeAsATransaction(Runnable actions) {
synchronized public void executeAsATransaction(Runnable actions) {
myDatabase.beginTransaction();
try {
actions.run();
@ -55,7 +55,7 @@ public final class ZLSQLiteConfig extends ZLConfig {
}
}
public void removeGroup(String name) {
synchronized public void removeGroup(String name) {
myDeleteGroupStatement.bindString(1, name);
try {
myDeleteGroupStatement.execute();
@ -63,7 +63,7 @@ public final class ZLSQLiteConfig extends ZLConfig {
}
}
public String getValue(String group, String name, String defaultValue) {
synchronized public String getValue(String group, String name, String defaultValue) {
String answer = defaultValue;
myGetValueStatement.bindString(1, group);
myGetValueStatement.bindString(2, name);
@ -74,7 +74,8 @@ public final class ZLSQLiteConfig extends ZLConfig {
return answer;
}
public void setValue(String group, String name, String value) {
synchronized public void setValue(String group, String name, String value) {
//System.err.println("g/n/v:" + group + ':' + name + ':' + value);
mySetValueStatement.bindString(1, group);
mySetValueStatement.bindString(2, name);
mySetValueStatement.bindString(3, value);
@ -84,7 +85,7 @@ public final class ZLSQLiteConfig extends ZLConfig {
}
}
public void unsetValue(String group, String name) {
synchronized public void unsetValue(String group, String name) {
myUnsetValueStatement.bindString(1, group);
myUnsetValueStatement.bindString(2, name);
try {

View file

@ -63,9 +63,34 @@ public class ZLAndroidWidget extends View {
myViewWidget = viewWidget;
}
public void onDraw(final Canvas canvas) {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (myScreenIsTouched) {
final ZLView view = ZLApplication.Instance().getCurrentView();
view.onStylusRelease(myTouchX, myTouchY);
myScrollingInProgress = false;
myScrollingShift = 0;
myScreenIsTouched = false;
}
}
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
final int w = getWidth();
final int h = getHeight();
if ((myMainBitmap != null) && ((myMainBitmap.getWidth() != w) || (myMainBitmap.getHeight() != h))) {
myMainBitmap = null;
}
if (myMainBitmap == null) {
myMainBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mySecondaryBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mySecondaryBitmapIsUpToDate = false;
drawOnBitmap(myMainBitmap);
}
if (myScrollingInProgress || (myScrollingShift != 0)) {
onDrawInScrolling(canvas);
} else {
@ -102,14 +127,16 @@ public class ZLAndroidWidget extends View {
Bitmap swap = myMainBitmap;
myMainBitmap = mySecondaryBitmap;
mySecondaryBitmap = swap;
mySecondaryBitmapIsUpToDate = false;
ZLApplication.Instance().getCurrentView().onScrollingFinished(0, (myScrollingBound < 0) ? 1 : -1);
}
mySecondaryBitmapIsUpToDate = false;
myScrollingInProgress = false;
myScrollingShift = 0;
} else {
if (shift < 0) {
shift += h;
}
// TODO: set color
canvas.drawLine(0, shift, w, shift, context.Paint);
if (myScrollingInProgress) {
postInvalidate();
@ -121,8 +148,12 @@ public class ZLAndroidWidget extends View {
if (myMainBitmap == null) {
return;
}
drawOnBitmap(mySecondaryBitmap);
if (((shift > 0) && (myScrollingShift <= 0)) ||
((shift < 0) && (myScrollingShift >= 0))) {
mySecondaryBitmapIsUpToDate = false;
}
myScrollingShift = shift;
drawOnBitmap(mySecondaryBitmap);
postInvalidate();
}
@ -179,31 +210,26 @@ public class ZLAndroidWidget extends View {
canvas.rotate(90, w / 2, w / 2);
break;
}
int dy = (bitmap == myMainBitmap) ? 0 : ((myScrollingShift > 0) ? 1 : 0);
int dy = (bitmap == myMainBitmap) ? 0 : ((myScrollingShift > 0) ? -1 : 1);
view.paint(0, dy);
context.endPaint();
}
private void onDrawStatic(Canvas canvas) {
final int w = getWidth();
final int h = getHeight();
if ((myMainBitmap != null) && ((myMainBitmap.getWidth() != w) || (myMainBitmap.getHeight() != h))) {
myMainBitmap = null;
}
if (myMainBitmap == null) {
myMainBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mySecondaryBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}
drawOnBitmap(myMainBitmap);
canvas.drawBitmap(myMainBitmap, 0, 0, ZLAndroidPaintContext.Instance().Paint);
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
ZLApplication.Instance().getCurrentView().onTrackballRotated((int)(10 * event.getX()), (int)(10 * event.getY()));
return true;
}
private boolean myScreenIsTouched;
private int myTouchX;
private int myTouchY;
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
@ -231,14 +257,18 @@ public class ZLAndroidWidget extends View {
break;
}
}
myTouchX = x;
myTouchY = y;
ZLView view = ZLApplication.Instance().getCurrentView();
final ZLView view = ZLApplication.Instance().getCurrentView();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
view.onStylusRelease(x, y);
myScreenIsTouched = false;
break;
case MotionEvent.ACTION_DOWN:
view.onStylusPress(x, y);
myScreenIsTouched = true;
break;
case MotionEvent.ACTION_MOVE:
view.onStylusMovePressed(x, y);

View file

@ -96,12 +96,11 @@ public class BookTextView extends FBView {
}
}
protected synchronized void preparePaintInfo() {
super.preparePaintInfo();
protected void onPreparePaintInfo() {
if (myPositionStack.isEmpty()) {
myPositionStack.add(new Position(myCurrentModelIndex, StartCursor));
myPositionStack.add(new Position(myCurrentModelIndex, getStartCursor()));
} else {
((Position)myPositionStack.get(myCurrentPointInStack)).set(StartCursor);
((Position)myPositionStack.get(myCurrentPointInStack)).set(getStartCursor());
((Position)myPositionStack.get(myCurrentPointInStack)).ModelIndex = myCurrentModelIndex;
// Position position = (Position)myPositionStack.get(myCurrentPointInStack);
@ -110,7 +109,7 @@ public class BookTextView extends FBView {
}
void scrollToHome() {
final ZLTextWordCursor cursor = StartCursor;
final ZLTextWordCursor cursor = getStartCursor();
if (!cursor.isNull() && cursor.isStartOfParagraph() && cursor.getParagraphCursor().Index == 0
&& myCurrentModelIndex == 0) {
return;
@ -121,7 +120,7 @@ public class BookTextView extends FBView {
gotoParagraph(0, false);
gotoPosition(0, 0, 0);
preparePaintInfo();
savePosition(position, 0, StartCursor);
savePosition(position, 0, getStartCursor());
ZLApplication.Instance().refreshWindow();
}
@ -129,12 +128,12 @@ public class BookTextView extends FBView {
void gotoParagraphSafe(int paragraphIndex) {
// gotoParagraphSafe(paragraphIndex, myCurrentModelIndex);
preparePaintInfo();
final ZLTextWordCursor cursor = StartCursor;
if (cursor != null) {
final ZLTextWordCursor cursor = getStartCursor();
if (!cursor.isNull()) {
final Position position = new Position(myCurrentModelIndex, cursor);
gotoParagraph(paragraphIndex, false);
preparePaintInfo();
savePosition(position, myCurrentModelIndex, StartCursor);
savePosition(position, myCurrentModelIndex, getStartCursor());
}
}
@ -144,13 +143,13 @@ public class BookTextView extends FBView {
void gotoParagraphSafe(int modelIndex, int paragraphIndex) {
preparePaintInfo();
final ZLTextWordCursor cursor = StartCursor;
if (cursor != null) {
final ZLTextWordCursor cursor = getStartCursor();
if (!cursor.isNull()) {
final Position position = new Position(myCurrentModelIndex, cursor);
setModelIndex(modelIndex);
gotoParagraph(paragraphIndex, false);
preparePaintInfo();
savePosition(position, modelIndex, StartCursor);
savePosition(position, modelIndex, getStartCursor());
}
}
@ -164,7 +163,7 @@ public class BookTextView extends FBView {
ZLTextElement element = area.Element;
if ((element instanceof ZLTextImageElement) ||
(element instanceof ZLTextWord)) {
final ZLTextWordCursor cursor = new ZLTextWordCursor(StartCursor);
final ZLTextWordCursor cursor = new ZLTextWordCursor(getStartCursor());
cursor.moveToParagraph(area.ParagraphIndex);
cursor.moveToParagraphStart();
final int elementIndex = area.TextElementIndex;

View file

@ -47,7 +47,7 @@ public abstract class FBView extends ZLTextViewImpl {
private int myStartX;
private int myStartY;
private boolean myTouchIsProcessed;
private boolean myScrollingIsActive;
public boolean onStylusPress(int x, int y) {
if (super.onStylusPress(x, y)) {
@ -56,38 +56,65 @@ public abstract class FBView extends ZLTextViewImpl {
myStartX = x;
myStartY = y;
myTouchIsProcessed = false;
myScrollingIsActive = true;
//activateSelection(x, y);
return true;
}
public boolean onStylusMovePressed(int x, int y) {
if (super.onStylusMovePressed(x, y) || myTouchIsProcessed) {
if (super.onStylusMovePressed(x, y)) {
return true;
}
final int diffY = y - myStartY;
if (Math.abs(diffY) * 5 >= Context.getHeight()) {
if (myScrollingIsActive) {
final int diffY = y - myStartY;
boolean doScroll = true;
if (diffY > 0) {
ZLApplication.Instance().doAction(ActionCode.TOUCH_SCROLL_BACKWARD);
} else {
ZLApplication.Instance().doAction(ActionCode.TOUCH_SCROLL_FORWARD);
ZLTextWordCursor cursor = getStartCursor();
doScroll = !cursor.isStartOfParagraph() || !cursor.getParagraphCursor().isFirst();
} else if (diffY < 0) {
ZLTextWordCursor cursor = getEndCursor();
doScroll = !cursor.isEndOfParagraph() || !cursor.getParagraphCursor().isLast();
}
if (doScroll) {
scrollTo(diffY);
return true;
}
myTouchIsProcessed = true;
return true;
}
return false;
}
public boolean onStylusRelease(int x, int y) {
boolean scrollingWasActive = myScrollingIsActive;
myScrollingIsActive = false;
if (super.onStylusRelease(x, y)) {
return true;
}
if (scrollingWasActive) {
final int diffY = y - myStartY;
boolean doScroll = false;
if (diffY > 0) {
ZLTextWordCursor cursor = getStartCursor();
doScroll = !cursor.isStartOfParagraph() || !cursor.getParagraphCursor().isFirst();
} else if (diffY < 0) {
ZLTextWordCursor cursor = getEndCursor();
doScroll = !cursor.isEndOfParagraph() || !cursor.getParagraphCursor().isLast();
}
if (doScroll) {
final int h = Context.getHeight();
final int w = Context.getWidth();
final int minDiff = (h > w) ? h / 4 : h / 3;
startAutoScrolling(Math.abs(diffY) >= minDiff);
return true;
}
}
//activateSelection(x, y);
return myTouchIsProcessed;
return false;
}
public boolean onTrackballRotated(int diffX, int diffY) {

View file

@ -31,6 +31,7 @@ abstract public class ZLView {
abstract public String getCaption();
abstract public void paint(int dx, int dy);
abstract public void onScrollingFinished(int dx, int dy);
public boolean onStylusPress(int x, int y) {
return false;

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2007-2009 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.zlibrary.text.view.impl;
interface PaintStateEnum {
int NOTHING_TO_PAINT = 0;
int READY = 1;
int START_IS_KNOWN = 2;
int END_IS_KNOWN = 3;
int TO_SCROLL_FORWARD = 4;
int TO_SCROLL_BACKWARD = 5;
};

View file

@ -0,0 +1,144 @@
/*
* Copyright (C) 2007-2009 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.zlibrary.text.view.impl;
import java.util.ArrayList;
final class ZLTextPage {
final ZLTextWordCursor StartCursor = new ZLTextWordCursor();
final ZLTextWordCursor EndCursor = new ZLTextWordCursor();
final ArrayList<ZLTextLineInfo> LineInfos = new ArrayList<ZLTextLineInfo>();
int PaintState = PaintStateEnum.NOTHING_TO_PAINT;
int OldWidth;
int OldHeight;
void reset() {
StartCursor.reset();
EndCursor.reset();
LineInfos.clear();
PaintState = PaintStateEnum.NOTHING_TO_PAINT;
}
void moveStartCursor(ZLTextParagraphCursor cursor) {
StartCursor.setCursor(cursor);
EndCursor.reset();
LineInfos.clear();
PaintState = PaintStateEnum.START_IS_KNOWN;
}
void moveStartCursor(int paragraphIndex, int wordIndex, int charIndex) {
if (StartCursor.isNull()) {
StartCursor.setCursor(EndCursor);
}
StartCursor.moveToParagraph(paragraphIndex);
StartCursor.moveTo(wordIndex, charIndex);
EndCursor.reset();
LineInfos.clear();
PaintState = PaintStateEnum.START_IS_KNOWN;
}
void moveEndCursor(int paragraphIndex, int wordIndex, int charIndex) {
if (EndCursor.isNull()) {
EndCursor.setCursor(StartCursor);
}
EndCursor.moveToParagraph(paragraphIndex);
if ((paragraphIndex > 0) && (wordIndex == 0) && (charIndex == 0)) {
EndCursor.previousParagraph();
EndCursor.moveToParagraphEnd();
} else {
EndCursor.moveTo(wordIndex, charIndex);
}
StartCursor.reset();
LineInfos.clear();
PaintState = PaintStateEnum.END_IS_KNOWN;
}
boolean isEmptyPage() {
for (ZLTextLineInfo info : LineInfos) {
if (info.IsVisible) {
return false;
}
}
return true;
}
void findLineFromStart(ZLTextWordCursor cursor, int overlappingValue) {
if (LineInfos.isEmpty() || (overlappingValue == 0)) {
cursor.reset();
return;
}
ZLTextLineInfo info = null;
for (ZLTextLineInfo i : LineInfos) {
info = i;
if (info.IsVisible) {
--overlappingValue;
if (overlappingValue == 0) {
break;
}
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.EndWordIndex, info.EndCharIndex);
}
void findLineFromEnd(ZLTextWordCursor cursor, int overlappingValue) {
if (LineInfos.isEmpty() || (overlappingValue == 0)) {
cursor.reset();
return;
}
final ArrayList<ZLTextLineInfo> infos = LineInfos;
final int size = infos.size();
ZLTextLineInfo info = null;
for (int i = size - 1; i >= 0; --i) {
info = infos.get(i);
if (info.IsVisible) {
--overlappingValue;
if (overlappingValue == 0) {
break;
}
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.StartWordIndex, info.StartCharIndex);
}
void findPercentFromStart(ZLTextWordCursor cursor, int areaHeight, int percent) {
if (LineInfos.isEmpty()) {
cursor.reset();
return;
}
int height = areaHeight * percent / 100;
boolean visibleLineOccured = false;
ZLTextLineInfo info = null;
for (ZLTextLineInfo i : LineInfos) {
info = i;
if (info.IsVisible) {
visibleLineOccured = true;
}
height -= info.Height + info.Descent + info.VSpaceAfter;
if (visibleLineOccured && (height <= 0)) {
break;
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.EndWordIndex, info.EndCharIndex);
}
}

View file

@ -163,7 +163,7 @@ public final class ZLTextParagraphCursor {
myElements.clear();
}
boolean isFirst() {
public boolean isFirst() {
return Index == 0;
}

View file

@ -30,10 +30,6 @@ import org.geometerplus.zlibrary.text.view.*;
import org.geometerplus.zlibrary.text.view.style.*;
public abstract class ZLTextViewImpl extends ZLTextView {
private static final int PREVIOUS_PAGE = -1;
private static final int CURRENT_PAGE = 0;
private static final int NEXT_PAGE = 1;
private ZLTextModel myModel;
protected int myCurrentModelIndex;
private ArrayList<ZLTextModel> myModelList;
@ -77,25 +73,13 @@ public abstract class ZLTextViewImpl extends ZLTextView {
int PIXEL_UNIT = 0;
int LINE_UNIT = 1;
};
private interface PaintState {
int NOTHING_TO_PAINT = 0;
int READY = 1;
int START_IS_KNOWN = 2;
int END_IS_KNOWN = 3;
int TO_SCROLL_FORWARD = 4;
int TO_SCROLL_BACKWARD = 5;
};
private int myPaintState = PaintState.NOTHING_TO_PAINT;
private int myScrollingMode;
private int myOverlappingValue;
private int myOldWidth;
private int myOldHeight;
private ZLTextPage myPreviousPage = new ZLTextPage();
private ZLTextPage myCurrentPage = new ZLTextPage();
private ZLTextPage myNextPage = new ZLTextPage();
public final ZLTextWordCursor StartCursor = new ZLTextWordCursor();
private final ZLTextWordCursor EndCursor = new ZLTextWordCursor();
private final ArrayList<ZLTextLineInfo> myLineInfos = new ArrayList<ZLTextLineInfo>();
private final HashMap<ZLTextLineInfo,ZLTextLineInfo> myLineInfoCache = new HashMap<ZLTextLineInfo,ZLTextLineInfo>();
private int[] myTextSize;
@ -130,9 +114,9 @@ public abstract class ZLTextViewImpl extends ZLTextView {
for (int i = 0; i < paragraphsNumber; ++i) {
myTextSize[i + 1] = myTextSize[i] + myModel.getParagraphTextLength(i);
}
StartCursor.setCursor(ZLTextParagraphCursor.cursor(myModel, 0));
EndCursor.reset();
myPaintState = PaintState.START_IS_KNOWN;
myCurrentPage.moveStartCursor(ZLTextParagraphCursor.cursor(myModel, 0));
myPreviousPage.reset();
myNextPage.reset();
}
}
}
@ -157,7 +141,7 @@ public abstract class ZLTextViewImpl extends ZLTextView {
public void highlightParagraph(int paragraphIndex) {
myModel.selectParagraph(paragraphIndex);
rebuildPaintInfo(true);
rebuildPaintInfo();
}
void setTextStyle(ZLTextStyle style) {
@ -274,17 +258,9 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
private void moveStartCursor(int paragraphIndex, int wordIndex, int charIndex) {
if (myPaintState == PaintState.NOTHING_TO_PAINT) {
return;
}
if (StartCursor.isNull()) {
StartCursor.setCursor(EndCursor);
}
StartCursor.moveToParagraph(paragraphIndex);
StartCursor.moveTo(wordIndex, charIndex);
EndCursor.reset();
myLineInfos.clear();
myPaintState = PaintState.START_IS_KNOWN;
myCurrentPage.moveStartCursor(paragraphIndex, wordIndex, charIndex);
myPreviousPage.reset();
myNextPage.reset();
}
private void moveEndCursor(int paragraphIndex) {
@ -292,59 +268,62 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
private void moveEndCursor(int paragraphIndex, int wordIndex, int charIndex) {
if (myPaintState == PaintState.NOTHING_TO_PAINT) {
return;
myCurrentPage.moveEndCursor(paragraphIndex, wordIndex, charIndex);
myPreviousPage.reset();
myNextPage.reset();
}
public ZLTextWordCursor getStartCursor() {
if (myCurrentPage.StartCursor.isNull()) {
preparePaintInfo(myCurrentPage);
}
if (EndCursor.isNull()) {
EndCursor.setCursor(StartCursor);
return myCurrentPage.StartCursor;
}
public ZLTextWordCursor getEndCursor() {
if (myCurrentPage.EndCursor.isNull()) {
preparePaintInfo(myCurrentPage);
}
EndCursor.moveToParagraph(paragraphIndex);
if ((paragraphIndex > 0) && (wordIndex == 0) && (charIndex == 0)) {
EndCursor.previousParagraph();
EndCursor.moveToParagraphEnd();
} else {
EndCursor.moveTo(wordIndex, charIndex);
}
StartCursor.reset();
myLineInfos.clear();
myPaintState = PaintState.END_IS_KNOWN;
return myCurrentPage.EndCursor;
}
public void gotoMark(ZLTextMark mark) {
myPreviousPage.reset();
myNextPage.reset();
if (mark.ParagraphIndex < 0) {
return;
}
boolean doRepaint = false;
if (StartCursor.isNull()) {
if (myCurrentPage.StartCursor.isNull()) {
doRepaint = true;
preparePaintInfo();
preparePaintInfo(myCurrentPage);
}
if (StartCursor.isNull()) {
if (myCurrentPage.StartCursor.isNull()) {
return;
}
final Position position = new Position(myCurrentModelIndex, StartCursor);
if ((StartCursor.getParagraphCursor().Index != mark.ParagraphIndex) || (StartCursor.getPosition().compareTo(mark) > 0)) {
final Position position = new Position(myCurrentModelIndex, myCurrentPage.StartCursor);
if ((myCurrentPage.StartCursor.getParagraphCursor().Index != mark.ParagraphIndex) || (myCurrentPage.StartCursor.getPosition().compareTo(mark) > 0)) {
doRepaint = true;
gotoParagraph(mark.ParagraphIndex, false);
preparePaintInfo();
preparePaintInfo(myCurrentPage);
}
if (EndCursor.isNull()) {
preparePaintInfo();
if (myCurrentPage.EndCursor.isNull()) {
preparePaintInfo(myCurrentPage);
}
while (mark.compareTo(EndCursor.getPosition()) > 0) {
while (mark.compareTo(myCurrentPage.EndCursor.getPosition()) > 0) {
doRepaint = true;
scrollPage(true, ScrollingMode.NO_OVERLAPPING, 0);
preparePaintInfo();
preparePaintInfo(myCurrentPage);
}
if (doRepaint) {
if (StartCursor.isNull()) {
preparePaintInfo();
if (myCurrentPage.StartCursor.isNull()) {
preparePaintInfo(myCurrentPage);
}
/* if (!position.equalsToCursor(StartCursor)) {
/* if (!position.equalsToCursor(myCurrentPage.StartCursor)) {
savePosition(position);
}
*/
savePosition(position, myCurrentModelIndex, StartCursor);
savePosition(position, myCurrentModelIndex, myCurrentPage.StartCursor);
ZLApplication.Instance().refreshWindow();
}
}
@ -370,9 +349,11 @@ public abstract class ZLTextViewImpl extends ZLTextView {
//To be written
}
myModel.search(text, startIndex, endIndex, ignoreCase);
if (!StartCursor.isNull()) {
rebuildPaintInfo(true);
ZLTextMark position = StartCursor.getPosition();
myPreviousPage.reset();
myNextPage.reset();
if (!myCurrentPage.StartCursor.isNull()) {
rebuildPaintInfo();
ZLTextMark position = myCurrentPage.StartCursor.getPosition();
gotoMark(wholeText ?
(backward ? myModel.getLastMark() : myModel.getFirstMark()) :
(backward ? myModel.getPreviousMark(position) : myModel.getNextMark(position)));
@ -381,26 +362,57 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
public boolean canFindNext() {
return !EndCursor.isNull() && (myModel != null) && (myModel.getNextMark(EndCursor.getPosition()).ParagraphIndex > -1);
final ZLTextWordCursor end = myCurrentPage.EndCursor;
return !end.isNull() && (myModel != null) && (myModel.getNextMark(end.getPosition()).ParagraphIndex > -1);
}
public void findNext() {
if (!EndCursor.isNull()) {
gotoMark(myModel.getNextMark(EndCursor.getPosition()));
final ZLTextWordCursor end = myCurrentPage.EndCursor;
if (!end.isNull()) {
gotoMark(myModel.getNextMark(end.getPosition()));
}
}
public boolean canFindPrevious() {
return !StartCursor.isNull() && (myModel != null) && (myModel.getPreviousMark(StartCursor.getPosition()).ParagraphIndex > -1);
final ZLTextWordCursor start = myCurrentPage.StartCursor;
return !start.isNull() && (myModel != null) && (myModel.getPreviousMark(start.getPosition()).ParagraphIndex > -1);
}
public void findPrevious() {
if (!StartCursor.isNull()) {
gotoMark(myModel.getPreviousMark(StartCursor.getPosition()));
final ZLTextWordCursor start = myCurrentPage.StartCursor;
if (!start.isNull()) {
gotoMark(myModel.getPreviousMark(start.getPosition()));
}
}
public synchronized void onScrollingFinished(int dx, int dy) {
if ((dx < 0) || (dy < 0)) {
ZLTextPage swap = myNextPage;
myNextPage = myCurrentPage;
myCurrentPage = myPreviousPage;
myPreviousPage = swap;
myPreviousPage.reset();
if (myCurrentPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {
preparePaintInfo(myNextPage);
myCurrentPage.EndCursor.setCursor(myNextPage.StartCursor);
myCurrentPage.PaintState = PaintStateEnum.START_IS_KNOWN;
}
} else if ((dx > 0) || (dy > 0)) {
ZLTextPage swap = myPreviousPage;
myPreviousPage = myCurrentPage;
myCurrentPage = myNextPage;
myNextPage = swap;
myNextPage.reset();
if (myCurrentPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {
preparePaintInfo(myPreviousPage);
myCurrentPage.StartCursor.setCursor(myPreviousPage.EndCursor);
myCurrentPage.PaintState = PaintStateEnum.END_IS_KNOWN;
}
}
}
public synchronized void paint(int dx, int dy) {
System.err.println("paint " + dx + ' ' + dy);
myTextElementMap.clear();
final ZLTextBaseStyle baseStyle = ZLTextStyleCollection.getInstance().getBaseStyle();
@ -411,16 +423,35 @@ public abstract class ZLTextViewImpl extends ZLTextView {
return;
}
preparePaintInfo();
ZLTextPage page;
if ((dx < 0) || (dy < 0)) {
page = myPreviousPage;
if (myPreviousPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {
preparePaintInfo(myCurrentPage);
myPreviousPage.EndCursor.setCursor(myCurrentPage.StartCursor);
myPreviousPage.PaintState = PaintStateEnum.END_IS_KNOWN;
}
} else if ((dx > 0) || (dy > 0)) {
page = myNextPage;
if (myNextPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {
preparePaintInfo(myCurrentPage);
myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);
myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;
}
} else {
page = myCurrentPage;
}
if (StartCursor.isNull() || EndCursor.isNull()) {
preparePaintInfo(page);
if (page.StartCursor.isNull() || page.EndCursor.isNull()) {
return;
}
{
final int fullScrollBarSize = myTextSize[myTextSize.length - 1];
final int scrollBarStart = sizeOfTextBeforeCursor(StartCursor);
final int scrollBarEnd = sizeOfTextBeforeCursor(EndCursor);
final int scrollBarStart = sizeOfTextBeforeCursor(page.StartCursor);
final int scrollBarEnd = sizeOfTextBeforeCursor(page.EndCursor);
setVerticalScrollbarParameters(
fullScrollBarSize,
scrollBarStart,
@ -428,7 +459,7 @@ public abstract class ZLTextViewImpl extends ZLTextView {
);
}
final ArrayList<ZLTextLineInfo> lineInfos = myLineInfos;
final ArrayList<ZLTextLineInfo> lineInfos = page.LineInfos;
final int[] labels = new int[lineInfos.size() + 1];
context.moveYTo(getTopMargin());
int index = 0;
@ -665,11 +696,11 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
}
private void buildInfos(final ZLTextWordCursor start, final ZLTextWordCursor result) {
private void buildInfos(ZLTextPage page, ZLTextWordCursor start, ZLTextWordCursor result) {
result.setCursor(start);
final ZLPaintContext context = Context;
int textAreaHeight = getTextAreaHeight();
myLineInfos.clear();
page.LineInfos.clear();
int counter = 0;
do {
resetTextStyle();
@ -686,7 +717,7 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
textAreaHeight -= info.VSpaceAfter;
result.moveTo(info.EndWordIndex, info.EndCharIndex);
myLineInfos.add(info);
page.LineInfos.add(info);
if (textAreaHeight < 0) {
break;
}
@ -957,9 +988,11 @@ public abstract class ZLTextViewImpl extends ZLTextView {
}
public void scrollPage(boolean forward, int scrollingMode, int value) {
preparePaintInfo();
if (myPaintState == PaintState.READY) {
myPaintState = forward ? PaintState.TO_SCROLL_FORWARD : PaintState.TO_SCROLL_BACKWARD;
preparePaintInfo(myCurrentPage);
myPreviousPage.reset();
myNextPage.reset();
if (myCurrentPage.PaintState == PaintStateEnum.READY) {
myCurrentPage.PaintState = forward ? PaintStateEnum.TO_SCROLL_FORWARD : PaintStateEnum.TO_SCROLL_BACKWARD;
myScrollingMode = scrollingMode;
myOverlappingValue = value;
}
@ -977,10 +1010,9 @@ public abstract class ZLTextViewImpl extends ZLTextView {
if (paragraphIndex < 0) {
paragraphIndex = 0;
}
StartCursor.setCursor(ZLTextParagraphCursor.cursor(myModel, paragraphIndex));
StartCursor.moveTo(wordIndex, charIndex);
EndCursor.reset();
myPaintState = PaintState.START_IS_KNOWN;
myCurrentPage.moveStartCursor(paragraphIndex, wordIndex, charIndex);
myPreviousPage.reset();
myNextPage.reset();
}
public final void gotoPosition(int modelIndex, int paragraphIndex, int wordIndex, int charIndex) {
@ -1008,216 +1040,164 @@ public abstract class ZLTextViewImpl extends ZLTextView {
return Math.max(Context.getWidth() - getLeftMargin() - getRightMargin(), 1);
}
protected synchronized void preparePaintInfo(/*int page*/) {
protected synchronized void preparePaintInfo() {
myPreviousPage.reset();
myNextPage.reset();
preparePaintInfo(myCurrentPage);
}
private synchronized void preparePaintInfo(ZLTextPage page) {
int newWidth = getViewWidth();
int newHeight = getTextAreaHeight();
if ((newWidth != myOldWidth) || (newHeight != myOldHeight)) {
myOldWidth = newWidth;
myOldHeight = newHeight;
rebuildPaintInfo(false);
if ((newWidth != page.OldWidth) || (newHeight != page.OldHeight)) {
page.OldWidth = newWidth;
page.OldHeight = newHeight;
if (page.PaintState != PaintStateEnum.NOTHING_TO_PAINT) {
page.LineInfos.clear();
if (!page.StartCursor.isNull()) {
page.EndCursor.reset();
page.PaintState = PaintStateEnum.START_IS_KNOWN;
} else if (!page.EndCursor.isNull()) {
page.StartCursor.reset();
page.PaintState = PaintStateEnum.END_IS_KNOWN;
}
}
}
if ((myPaintState == PaintState.NOTHING_TO_PAINT) || (myPaintState == PaintState.READY)) {
if ((page.PaintState == PaintStateEnum.NOTHING_TO_PAINT) || (page.PaintState == PaintStateEnum.READY)) {
return;
}
final HashMap<ZLTextLineInfo,ZLTextLineInfo> cache = myLineInfoCache;
for (ZLTextLineInfo info : myLineInfos) {
for (ZLTextLineInfo info : page.LineInfos) {
cache.put(info, info);
}
switch (myPaintState) {
switch (page.PaintState) {
default:
break;
case PaintState.TO_SCROLL_FORWARD:
if (!EndCursor.getParagraphCursor().isLast() || !EndCursor.isEndOfParagraph()) {
case PaintStateEnum.TO_SCROLL_FORWARD:
if (!page.EndCursor.getParagraphCursor().isLast() || !page.EndCursor.isEndOfParagraph()) {
final ZLTextWordCursor startCursor = new ZLTextWordCursor();
switch (myScrollingMode) {
case ScrollingMode.NO_OVERLAPPING:
break;
case ScrollingMode.KEEP_LINES:
findLineFromEnd(startCursor, myOverlappingValue);
page.findLineFromEnd(startCursor, myOverlappingValue);
break;
case ScrollingMode.SCROLL_LINES:
findLineFromStart(startCursor, myOverlappingValue);
page.findLineFromStart(startCursor, myOverlappingValue);
if (startCursor.isEndOfParagraph()) {
startCursor.nextParagraph();
}
break;
case ScrollingMode.SCROLL_PERCENTAGE:
findPercentFromStart(startCursor, myOverlappingValue);
page.findPercentFromStart(startCursor, getTextAreaHeight(), myOverlappingValue);
break;
}
if (!startCursor.isNull() && startCursor.equalsToCursor(StartCursor)) {
findLineFromStart(startCursor, 1);
if (!startCursor.isNull() && startCursor.equalsToCursor(page.StartCursor)) {
page.findLineFromStart(startCursor, 1);
}
if (!startCursor.isNull()) {
final ZLTextWordCursor endCursor = new ZLTextWordCursor();
buildInfos(startCursor, endCursor);
if (!pageIsEmpty() && ((myScrollingMode != ScrollingMode.KEEP_LINES) || (!endCursor.equalsToCursor(EndCursor)))) {
StartCursor.setCursor(startCursor);
EndCursor.setCursor(endCursor);
buildInfos(page, startCursor, endCursor);
if (!page.isEmptyPage() && ((myScrollingMode != ScrollingMode.KEEP_LINES) || (!endCursor.equalsToCursor(page.EndCursor)))) {
page.StartCursor.setCursor(startCursor);
page.EndCursor.setCursor(endCursor);
break;
}
}
StartCursor.setCursor(EndCursor);
buildInfos(StartCursor, EndCursor);
page.StartCursor.setCursor(page.EndCursor);
buildInfos(page, page.StartCursor, page.EndCursor);
}
break;
case PaintState.TO_SCROLL_BACKWARD:
if (!StartCursor.getParagraphCursor().isFirst() || !StartCursor.isStartOfParagraph()) {
case PaintStateEnum.TO_SCROLL_BACKWARD:
if (!page.StartCursor.getParagraphCursor().isFirst() || !page.StartCursor.isStartOfParagraph()) {
switch (myScrollingMode) {
case ScrollingMode.NO_OVERLAPPING:
StartCursor.setCursor(findStart(StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
break;
case ScrollingMode.KEEP_LINES:
{
ZLTextWordCursor endCursor = new ZLTextWordCursor();
findLineFromStart(endCursor, myOverlappingValue);
if (!endCursor.isNull() && endCursor.equalsToCursor(EndCursor)) {
findLineFromEnd(endCursor, 1);
page.findLineFromStart(endCursor, myOverlappingValue);
if (!endCursor.isNull() && endCursor.equalsToCursor(page.EndCursor)) {
page.findLineFromEnd(endCursor, 1);
}
if (!endCursor.isNull()) {
ZLTextWordCursor startCursor = findStart(endCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight());
if (startCursor.equalsToCursor(StartCursor)) {
StartCursor.setCursor(findStart(StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
if (startCursor.equalsToCursor(page.StartCursor)) {
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
} else {
StartCursor.setCursor(startCursor);
page.StartCursor.setCursor(startCursor);
}
} else {
StartCursor.setCursor(findStart(StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
}
break;
}
case ScrollingMode.SCROLL_LINES:
StartCursor.setCursor(findStart(StartCursor, SizeUnit.LINE_UNIT, myOverlappingValue));
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.LINE_UNIT, myOverlappingValue));
break;
case ScrollingMode.SCROLL_PERCENTAGE:
StartCursor.setCursor(findStart(StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight() * myOverlappingValue / 100));
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight() * myOverlappingValue / 100));
break;
}
buildInfos(StartCursor, EndCursor);
if (pageIsEmpty()) {
StartCursor.setCursor(findStart(StartCursor, SizeUnit.LINE_UNIT, 1));
buildInfos(StartCursor, EndCursor);
buildInfos(page, page.StartCursor, page.EndCursor);
if (page.isEmptyPage()) {
page.StartCursor.setCursor(findStart(page.StartCursor, SizeUnit.LINE_UNIT, 1));
buildInfos(page, page.StartCursor, page.EndCursor);
}
}
break;
case PaintState.START_IS_KNOWN:
buildInfos(StartCursor, EndCursor);
case PaintStateEnum.START_IS_KNOWN:
buildInfos(page, page.StartCursor, page.EndCursor);
break;
case PaintState.END_IS_KNOWN:
StartCursor.setCursor(findStart(EndCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
buildInfos(StartCursor, EndCursor);
case PaintStateEnum.END_IS_KNOWN:
page.StartCursor.setCursor(findStart(page.EndCursor, SizeUnit.PIXEL_UNIT, getTextAreaHeight()));
buildInfos(page, page.StartCursor, page.EndCursor);
break;
}
myPaintState = PaintState.READY;
page.PaintState = PaintStateEnum.READY;
// TODO: cache?
myLineInfoCache.clear();
}
boolean pageIsEmpty() {
for (ZLTextLineInfo info : myLineInfos) {
if (info.IsVisible) {
return false;
}
}
return true;
}
private void findLineFromStart(ZLTextWordCursor cursor, int overlappingValue) {
if (myLineInfos.isEmpty() || (overlappingValue == 0)) {
cursor.reset();
} else {
ZLTextLineInfo info = null;
for (ZLTextLineInfo i : myLineInfos) {
info = i;
if (info.IsVisible) {
--overlappingValue;
if (overlappingValue == 0) {
break;
}
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.EndWordIndex, info.EndCharIndex);
if (page == myCurrentPage) {
myPreviousPage.reset();
myNextPage.reset();
onPreparePaintInfo();
}
}
void findLineFromEnd(ZLTextWordCursor cursor, int overlappingValue) {
if (myLineInfos.isEmpty() || (overlappingValue == 0)) {
cursor.reset();
} else {
final ArrayList<ZLTextLineInfo> infos = myLineInfos;
final int size = infos.size();
ZLTextLineInfo info = null;
for (int i = size - 1; i >= 0; --i) {
info = infos.get(i);
if (info.IsVisible) {
--overlappingValue;
if (overlappingValue == 0) {
break;
}
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.StartWordIndex, info.StartCharIndex);
}
}
private void findPercentFromStart(ZLTextWordCursor cursor, int percent) {
if (myLineInfos.isEmpty()) {
cursor.reset();
} else {
int height = getTextAreaHeight() * percent / 100;
boolean visibleLineOccured = false;
ZLTextLineInfo info = null;
for (ZLTextLineInfo i : myLineInfos) {
info = i;
if (info.IsVisible) {
visibleLineOccured = true;
}
height -= info.Height + info.Descent + info.VSpaceAfter;
if (visibleLineOccured && (height <= 0)) {
break;
}
}
cursor.setCursor(info.ParagraphCursor);
cursor.moveTo(info.EndWordIndex, info.EndCharIndex);
}
protected void onPreparePaintInfo() {
}
public void clearCaches() {
rebuildPaintInfo(true);
rebuildPaintInfo();
}
protected void rebuildPaintInfo(boolean strong) {
if (strong) {
ZLTextParagraphCursorCache.clear();
}
protected void rebuildPaintInfo() {
myPreviousPage.reset();
myNextPage.reset();
ZLTextParagraphCursorCache.clear();
if (myPaintState != PaintState.NOTHING_TO_PAINT) {
myLineInfos.clear();
if (!StartCursor.isNull()) {
if (strong) {
StartCursor.rebuild();
}
EndCursor.reset();
myPaintState = PaintState.START_IS_KNOWN;
} else if (!EndCursor.isNull()) {
if (strong) {
EndCursor.rebuild();
}
StartCursor.reset();
myPaintState = PaintState.END_IS_KNOWN;
if (myCurrentPage.PaintState != PaintStateEnum.NOTHING_TO_PAINT) {
myCurrentPage.LineInfos.clear();
if (!myCurrentPage.StartCursor.isNull()) {
myCurrentPage.StartCursor.rebuild();
myCurrentPage.EndCursor.reset();
myCurrentPage.PaintState = PaintStateEnum.START_IS_KNOWN;
} else if (!myCurrentPage.EndCursor.isNull()) {
myCurrentPage.EndCursor.rebuild();
myCurrentPage.StartCursor.reset();
myCurrentPage.PaintState = PaintStateEnum.END_IS_KNOWN;
}
}
if (strong) {
myLineInfoCache.clear();
}
myLineInfoCache.clear();
}
private int infoSize(ZLTextLineInfo info, int unit) {

View file

@ -39,9 +39,9 @@ public class ZLTextBaseStyle implements ZLTextStyle {
public final ZLColorOption RegularTextColorOption =
new ZLColorOption(COLORS, "Text", new ZLColor(0, 0, 0));
public final ZLColorOption InternalHyperlinkTextColorOption =
new ZLColorOption(COLORS, "Hyperlink", new ZLColor(33, 96, 180));
new ZLColorOption(COLORS, "Hyperlink", new ZLColor(60, 139, 255));
public final ZLColorOption ExternalHyperlinkTextColorOption =
new ZLColorOption(COLORS, "ExternalHyperlink", new ZLColor(98, 174, 26));
new ZLColorOption(COLORS, "ExternalHyperlink", new ZLColor(33, 96, 180));
public final ZLBooleanOption AutoHyphenationOption =
new ZLBooleanOption(OPTIONS, "AutoHyphenation", true);