void ZLTextView::search(const std::string &text, bool ignoreCase, bool wholeText, bool backward, bool thisSectionOnly) { shared_ptr<ZLTextModel> model = textArea().model(); if (model.isNull() || text.empty()) { return; } size_t startIndex = 0; size_t endIndex = model->paragraphsNumber(); if (thisSectionOnly) { std::vector<size_t>::const_iterator i = nextBreakIterator(); if (i != myTextBreaks.begin()) { startIndex = *(i - 1); } if (i != myTextBreaks.end()) { endIndex = *i; } } model->search(text, startIndex, endIndex, ignoreCase); const ZLTextWordCursor &startCursor = textArea().startCursor(); if (!startCursor.isNull()) { myTextAreaController.rebuildPaintInfo(true); ZLTextMark position = startCursor.position(); gotoMark(wholeText ? (backward ? model->lastMark() : model->firstMark()) : (backward ? model->previousMark(position) : model->nextMark(position))); ZLApplication::Instance().refreshWindow(); } }
void ZLTextView::onScrollbarMoved(Direction direction, size_t full, size_t from, size_t to) { if (direction != VERTICAL) { return; } myTextAreaController.area().selectionModel().deactivate(); if (textArea().model().isNull()) { return; } if (textArea().startCursor().isNull() || textArea().endCursor().isNull()) { return; } myTreeStateIsFrozen = true; if (from == 0) { scrollToStartOfText(); } else if (to == full) { scrollToEndOfText(); } else { gotoCharIndex(to); } preparePaintInfo(); myTreeStateIsFrozen = false; myDoUpdateScrollbar = false; ZLApplication::Instance().refreshWindow(); }
size_t ZLTextView::pageNumber() const { if (textArea().isEmpty()) { return 0; } std::vector<size_t>::const_iterator i = nextBreakIterator(); const size_t startIndex = (i != myTextBreaks.begin()) ? *(i - 1) : 0; const size_t endIndex = (i != myTextBreaks.end()) ? *i : textArea().model()->paragraphsNumber(); return (myTextSize[endIndex] - myTextSize[startIndex]) / 2048 + 1; }
std::vector<size_t>::const_iterator ZLTextView::nextBreakIterator() const { ZLTextWordCursor cursor = textArea().endCursor(); if (cursor.isNull()) { cursor = textArea().startCursor(); } if (cursor.isNull()) { return myTextBreaks.begin(); } return std::lower_bound(myTextBreaks.begin(), myTextBreaks.end(), cursor.paragraphCursor().index()); }
void BookTextView::scrollToHome() { if (!textArea().startCursor().isNull() && textArea().startCursor().isStartOfParagraph() && textArea().startCursor().paragraphCursor().index() == 0) { return; } gotoParagraph(0, false); FBReader::Instance().refreshWindow(); }
void ZLTextView::paint() { context().clear(backgroundColor()); // PB // myTextAreaController.area().setOffsets( // textArea().isRtl() ? rightMargin() : leftMargin(), topMargin() // ); myTextAreaController.area().setOffsets(0, 0); // if (!) preparePaintInfo(); ////<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<, if (textArea().isEmpty()) { return; } if (!ZLNXPaintContext::lock_drawing) myTextAreaController.area().paint(); /////<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< shared_ptr<ZLTextPositionIndicatorInfo> indicatorInfo = this->indicatorInfo(); if (!indicatorInfo.isNull() && (indicatorInfo->type() == ZLTextPositionIndicatorInfo::FB_INDICATOR)) { positionIndicator()->draw(); } if (myDoUpdateScrollbar && !indicatorInfo.isNull()) { myDoUpdateScrollbar = false; const size_t full = positionIndicator()->sizeOfTextBeforeParagraph(positionIndicator()->endTextIndex()); const size_t from = positionIndicator()->sizeOfTextBeforeCursor(textArea().startCursor()); const size_t to = positionIndicator()->sizeOfTextBeforeCursor(textArea().endCursor()); bool showScrollbar = (indicatorInfo->type() == ZLTextPositionIndicatorInfo::OS_SCROLLBAR) && (to - from < full); if (showScrollbar) { setScrollbarEnabled(VERTICAL, true); setScrollbarParameters(VERTICAL, full, from, to); } else { setScrollbarEnabled(VERTICAL, false); } } ZLTextParagraphCursorCache::cleanup(); }
void ZLTextView::gotoParagraph(int num, bool end) { shared_ptr<ZLTextModel> model = textArea().model(); if (model.isNull()) { return; } const ZLTextWordCursor &startCursor = textArea().startCursor(); const ZLTextWordCursor &endCursor = textArea().endCursor(); if (!startCursor.isNull() && startCursor.isStartOfParagraph() && startCursor.paragraphCursor().isFirst() && (num >= (int)startCursor.paragraphCursor().index()) && !endCursor.isNull() && endCursor.isEndOfParagraph() && endCursor.paragraphCursor().isLast() && (num <= (int)endCursor.paragraphCursor().index())) { return; } if (model->kind() == ZLTextModel::TREE_MODEL) { if ((num >= 0) && (num < (int)model->paragraphsNumber())) { ZLTextTreeParagraph *tp = (ZLTextTreeParagraph*)(*model)[num]; if (myTreeStateIsFrozen) { int corrected = num; ZLTextTreeParagraph *visible = tp; for (ZLTextTreeParagraph *parent = tp->parent(); parent != 0; parent = parent->parent()) { if (!parent->isOpen()) { visible = parent; } } if (visible != tp) { for (--corrected; ((corrected > 0) && visible != (*model)[corrected]); --corrected) { } } if (end && (corrected != num)) { ++corrected; } num = corrected; } else { tp->openTree(); myTextAreaController.rebuildPaintInfo(true); } } } if (end) { if ((num > 0) && (num <= (int)model->paragraphsNumber())) { myTextAreaController.moveEndCursor(num); } } else { if ((num >= 0) && (num < (int)model->paragraphsNumber())) { myTextAreaController.moveStartCursor(num); } } }
bool ZLTextView::onStylusMove(int x, int y) { shared_ptr<ZLTextModel> model = textArea().model(); if (!model.isNull()) { if (model->kind() == ZLTextModel::TREE_MODEL) { const ZLTextTreeNodeRectangle *node = textArea().treeNodeByCoordinates(x, y); if (node != 0) { ZLApplication::Instance().setHyperlinkCursor(true); return true; } } ZLApplication::Instance().setHyperlinkCursor(false); } return false; }
bool ContentsView::_onStylusMove(int x, int y) { FBReader &fbreader = FBReader::Instance(); int index = textArea().paragraphIndexByCoordinates(x, y); if ((index < 0) || ((int)textArea().model()->paragraphsNumber() <= index)) { fbreader.setHyperlinkCursor(false); return true; } const ContentsModel &contentsModel = (const ContentsModel&)*textArea().model(); const ZLTextTreeParagraph *paragraph = (const ZLTextTreeParagraph*)contentsModel[index]; fbreader.setHyperlinkCursor(contentsModel.reference(paragraph) >= 0); return true; }
void ZLTextView::paint() { context().clear(backgroundColor()); myTextAreaController.area().setOffsets( textArea().isRtl() ? rightMargin() : leftMargin(), topMargin() + headerHeight() ); preparePaintInfo(); if (textArea().isEmpty()) { return; } myTextAreaController.area().paint(); shared_ptr<ZLTextPositionIndicatorInfo> indicatorInfo = this->indicatorInfo(); if (!indicatorInfo.isNull()) { switch (indicatorInfo->type()) { default: break; case ZLTextPositionIndicatorInfo::PAGE_FOOTER: positionIndicator()->draw(); break; case ZLTextPositionIndicatorInfo::PAGE_HEADER: paintHeader(); break; } } if (myDoUpdateScrollbar && !indicatorInfo.isNull()) { myDoUpdateScrollbar = false; const std::size_t full = sizeOfTextBeforeParagraph(endTextIndex()); const std::size_t from = sizeOfTextBeforeCursor(textArea().startCursor()); const std::size_t to = sizeOfTextBeforeCursor(textArea().endCursor()); bool showScrollbar = (indicatorInfo->type() == ZLTextPositionIndicatorInfo::OS_SCROLLBAR) && (to - from < full); if (showScrollbar) { setScrollbarEnabled(VERTICAL, true); setScrollbarParameters(VERTICAL, full, from, to); } else { setScrollbarEnabled(VERTICAL, false); } } ZLTextParagraphCursorCache::cleanup(); }
bool ZLTextView::onStylusClick(int x, int y, int count) { AppLog("ZLTextView::onStylusClick count=%d",count); if (count > 20) { return true; } else if (count > 10) { myTextAreaController.area().selectionModel().extendWordSelectionToParagraph(); ZLApplication::Instance().refreshWindow(); myDoubleClickInfo.Count = 20; return true; } else if (count > 2) { AppLog("ZLTextView::onStylusClick count > 2"); if (myTextAreaController.area().selectionModel().selectWord(textArea().realX(x), y)) { AppLog("selectWord(textArea"); ZLApplication::Instance().refreshWindow(); myDoubleClickInfo.Count = 10; return true; } else { AppLog("ZLTextView::onStylusClick xxx"); myDoubleClickInfo.Count = 0; } } else { AppLog("ZLTextView::onStylusClick 1"); myTextAreaController.area().selectionModel().clear(); //ZLApplication::Instance().refreshWindow(); return false; } AppLog("ZLTextView::onStylusClick 2"); return true; }
void ZLTextView::scrollToStartOfText() { if (textArea().endCursor().isNull()) { return; } const ZLTextWordCursor &startCursor = textArea().startCursor(); if (!startCursor.isNull() && startCursor.isStartOfParagraph() && startCursor.paragraphCursor().isFirst()) { return; } std::vector<size_t>::const_iterator i = nextBreakIterator(); gotoParagraph((i != myTextBreaks.begin()) ? *(i - 1) : 0, false); ZLApplication::Instance().refreshWindow(); }
bool BookTextView::_onStylusMove(int x, int y) { const ZLTextElementRectangle *rectangle = textArea().elementByCoordinates(x, y); std::string id; ZLHyperlinkType type; FBReader::Instance().setHyperlinkCursor((rectangle != 0) && getHyperlinkInfo(*rectangle, id, type)); return true; }
bool BookTextView::getHyperlinkInfo(const ZLTextElementRectangle &rectangle, std::string &id, ZLHyperlinkType &type) const { if ((rectangle.Kind != ZLTextElement::WORD_ELEMENT) && (rectangle.Kind != ZLTextElement::IMAGE_ELEMENT)) { return false; } ZLTextWordCursor cursor = textArea().startCursor(); cursor.moveToParagraph(rectangle.ParagraphIndex); cursor.moveToParagraphStart(); ZLTextKind hyperlinkKind = REGULAR; for (int i = 0; i < rectangle.ElementIndex; ++i) { const ZLTextElement &element = cursor.element(); if (element.kind() == ZLTextElement::CONTROL_ELEMENT) { const ZLTextControlEntry &control = ((const ZLTextControlElement&)element).entry(); if (control.isHyperlink()) { hyperlinkKind = control.kind(); id = ((const ZLTextHyperlinkControlEntry&)control).label(); type = ((const ZLTextHyperlinkControlEntry&)control).hyperlinkType(); } else if (!control.isStart() && (control.kind() == hyperlinkKind)) { hyperlinkKind = REGULAR; } } cursor.nextWord(); } return hyperlinkKind != REGULAR; }
bool BookTextView::_onStylusRelease(int x, int y) { FBReader &fbreader = FBReader::Instance(); if (!isReleasedWithoutMotion()) { return false; } const ZLTextElementRectangle *rectangle = textArea().elementByCoordinates(x, y); if (rectangle != 0) { std::string id; ZLHyperlinkType type; if (getHyperlinkInfo(*rectangle, id, type)) { fbreader.tryShowFootnoteView(id, type); return true; } if (fbreader.isDictionarySupported() && fbreader.EnableSingleClickDictionaryOption.value()) { const std::string txt = word(*rectangle); if (!txt.empty()) { fbreader.openInDictionary(txt); return true; } } } return false; }
const BooksPos BooksTextView::rewind() { SUPER::gotoPosition(0, 0, 0); preparePaintInfo(); if (!textArea().isVisible()) nextPage(); return position(); }
bool BookTextView::canUndoPageMove() { if (textArea().isEmpty()) { return false; } if (myCurrentPointInStack == 0) { return false; } if ((myCurrentPointInStack == 1) && (myPositionStack.size() == 1)) { const ZLTextWordCursor &cursor = textArea().startCursor(); if (!cursor.isNull()) { return myPositionStack.back() != cursorPosition(cursor); } } return true; }
void BookTextView::replaceCurrentPositionInStack() { const ZLTextWordCursor &cursor = textArea().startCursor(); if (!cursor.isNull()) { myPositionStack[myCurrentPointInStack] = cursorPosition(cursor); myStackChanged = true; } }
void ContentsView::gotoReference() { textArea().model()->removeAllMarks(); const size_t selected = currentTextViewParagraph(); highlightParagraph(selected); preparePaintInfo(); gotoParagraph(selected); scrollPage(false, ZLTextAreaController::SCROLL_PERCENTAGE, 40); }
void ZLTextView::gotoPosition(int paragraphIndex, int elementIndex, int charIndex) { gotoParagraph(paragraphIndex, false); const ZLTextWordCursor &startCursor = textArea().startCursor(); if (!startCursor.isNull() && ((int)startCursor.paragraphCursor().index() == paragraphIndex)) { myTextAreaController.moveStartCursor(paragraphIndex, elementIndex, charIndex); } }
bool ContentsView::_onStylusPress(int x, int y) { FBReader &fbreader = FBReader::Instance(); const ContentsModel &contentsModel = (const ContentsModel&)*textArea().model(); int index = textArea().paragraphIndexByCoordinates(x, y); if ((index < 0) || ((int)contentsModel.paragraphsNumber() <= index)) { return false; } const ZLTextTreeParagraph *paragraph = (const ZLTextTreeParagraph*)contentsModel[index]; int reference = contentsModel.reference(paragraph); if (reference >= 0) { fbreader.bookTextView().gotoParagraph(reference); fbreader.showBookTextView(); } return true; }
void ZLTextView::gotoCharIndex(size_t charIndex) { shared_ptr<ZLTextModel> model = textArea().model(); if (model.isNull() || positionIndicator().isNull()) { return; } std::vector<size_t>::const_iterator i = nextBreakIterator(); const size_t startParagraphIndex = (i != myTextBreaks.begin()) ? *(i - 1) + 1 : 0; const size_t endParagraphIndex = (i != myTextBreaks.end()) ? *i : model->paragraphsNumber(); const size_t fullTextSize = myTextSize[endParagraphIndex] - myTextSize[startParagraphIndex]; charIndex = std::min(charIndex, fullTextSize - 1); std::vector<size_t>::const_iterator j = std::lower_bound(myTextSize.begin(), myTextSize.end(), charIndex + myTextSize[startParagraphIndex]); size_t paragraphIndex = j - myTextSize.begin(); if ((*model)[paragraphIndex]->kind() == ZLTextParagraph::END_OF_SECTION_PARAGRAPH) { gotoParagraph(paragraphIndex, true); return; } if (paragraphIndex > startParagraphIndex) { --paragraphIndex; } gotoParagraph(paragraphIndex, false); preparePaintInfo(); if (!positionIndicator().isNull()) { size_t endCharIndex = positionIndicator()->sizeOfTextBeforeCursor(textArea().endCursor()); if (endCharIndex > charIndex) { while (endCharIndex > charIndex) { scrollPage(false, ZLTextAreaController::SCROLL_LINES, 1); preparePaintInfo(); if (positionIndicator()->sizeOfTextBeforeCursor(textArea().startCursor()) <= myTextSize[startParagraphIndex]) { break; } endCharIndex = positionIndicator()->sizeOfTextBeforeCursor(textArea().endCursor()); } if (endCharIndex < charIndex) { scrollPage(true, ZLTextAreaController::SCROLL_LINES, 1); } } else { int startCharIndex = positionIndicator()->sizeOfTextBeforeCursor(textArea().startCursor()); while (endCharIndex < charIndex) { scrollPage(true, ZLTextAreaController::SCROLL_LINES, 1); preparePaintInfo(); const int newStartCharIndex = positionIndicator()->sizeOfTextBeforeCursor(textArea().startCursor()); if (newStartCharIndex <= startCharIndex) { break; } startCharIndex = newStartCharIndex; endCharIndex = positionIndicator()->sizeOfTextBeforeCursor(textArea().endCursor()); } if (endCharIndex > charIndex) { scrollPage(false, ZLTextAreaController::SCROLL_LINES, 1); } } } }
void ZLTextView::scrollToEndOfText() { shared_ptr<ZLTextModel> model = textArea().model(); if (textArea().endCursor().isNull() || model.isNull()) { return; } if (textArea().endCursor().isEndOfParagraph() && textArea().endCursor().paragraphCursor().isLast()) { return; } std::vector<size_t>::const_iterator i = nextBreakIterator(); if (i == myTextBreaks.end()) { gotoParagraph(model->paragraphsNumber(), true); myTextAreaController.area().myEndCursor.nextParagraph(); } else { gotoParagraph(*i - 1, true); } myTextAreaController.area().myEndCursor.moveToParagraphEnd(); ZLApplication::Instance().refreshWindow(); }
void ZLTextView::gotoMark(ZLTextMark mark) { if (mark.ParagraphIndex < 0) { return; } bool doRepaint = false; if (textArea().startCursor().isNull()) { doRepaint = true; preparePaintInfo(); } if (textArea().startCursor().isNull()) { return; } if (((int)textArea().startCursor().paragraphCursor().index() != mark.ParagraphIndex) || (textArea().startCursor().position() > mark)) { doRepaint = true; gotoParagraph(mark.ParagraphIndex); preparePaintInfo(); } if (textArea().endCursor().isNull()) { preparePaintInfo(); } while (mark > textArea().endCursor().position()) { doRepaint = true; scrollPage(true, ZLTextAreaController::NO_OVERLAPPING, 0); preparePaintInfo(); } if (doRepaint) { ZLApplication::Instance().refreshWindow(); } }
/************************************************************************* Scroll the view so that the current carat position is visible. *************************************************************************/ void MultiLineEditbox::ensureCaratIsVisible(void) { // calculate the location of the carat const FontBase* fnt = getFont(); size_t caratLine = getLineNumberFromIndex(d_caratPos); if (caratLine < d_lines.size()) { Rect textArea(getTextRenderArea()); size_t caratLineIdx = d_caratPos - d_lines[caratLine].d_startIdx; float ypos = caratLine * fnt->getLineSpacing(); float xpos = fnt->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, caratLineIdx)); // adjust position for scroll bars if( d_horzScrollbar ) xpos -= d_horzScrollbar->getScrollPosition(); if( d_vertScrollbar ) ypos -= d_vertScrollbar->getScrollPosition(); // if carat is above window, scroll up if (ypos < 0) { if( d_vertScrollbar ) d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + ypos); } // if carat is below the window, scroll down else if ((ypos += fnt->getLineSpacing()) > textArea.getHeight()) { if( d_vertScrollbar ) d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + (ypos - textArea.getHeight()) + fnt->getLineSpacing()); } // if carat is left of the window, scroll left if (xpos < 0) { if( d_horzScrollbar ) d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + xpos - 50); } // if carat is right of the window, scroll right else if (xpos > textArea.getWidth()) { if( d_horzScrollbar ) d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + (xpos - textArea.getWidth()) + 50); } } }
void ZLTextView::gotoPage(size_t index) { size_t charIndex = (index - 1) * 2048; std::vector<size_t>::const_iterator it = std::lower_bound(myTextSize.begin(), myTextSize.end(), charIndex); const int paraIndex = it - myTextSize.begin(); const ZLTextParagraph ¶ = *(*textArea().model())[paraIndex]; switch (para.kind()) { case ZLTextParagraph::END_OF_TEXT_PARAGRAPH: case ZLTextParagraph::END_OF_SECTION_PARAGRAPH: charIndex = myTextSize[paraIndex - 1]; break; default: break; } gotoCharIndex(charIndex); }
void BookTextView::gotoParagraph(int num, bool end) { if (textArea().isEmpty()) { return; } if (!myLockUndoStackChanges) { if (myPositionStack.size() > myCurrentPointInStack) { myPositionStack.erase(myPositionStack.begin() + myCurrentPointInStack, myPositionStack.end()); myStackChanged = true; } pushCurrentPositionIntoStack(false); myCurrentPointInStack = myPositionStack.size(); } FBView::gotoParagraph(num, end); }
bool BooksTextView::nextPage() { BooksPos saved(position()); BooksPos current(saved); do { scrollPage(true, ZLTextAreaController::NO_OVERLAPPING, 1); preparePaintInfo(); const BooksPos pos = position(); if (pos == current) { gotoPosition(saved); return false; } current = pos; } while (!textArea().isVisible()); return true; }
void BookTextView::paintHeader() const { const int unit = baseStyle()->fontSize() / 4; const int left = leftMargin(); const int right = context().width() - rightMargin() - 1; const int bottom = topMargin() + unit * 4; context().setColor(color(ZLTextStyle::REGULAR_TEXT)); context().setFont(baseStyle()->fontFamily(), unit * 3, false, true); context().drawLine(left, bottom, right, bottom); // TODO: use chapter name instead const std::string leftText = myBook->title(); context().drawString(left, bottom - unit, leftText.c_str(), leftText.length(), false); std::string rightText; ZLStringUtil::appendNumber(rightText, 1 + sizeOfTextBeforeCursor(textArea().endCursor()) / 2048); rightText += '/'; ZLStringUtil::appendNumber(rightText, 1 + sizeOfTextBeforeParagraph(endTextIndex()) / 2048); const std::size_t rightTextWidth = context().stringWidth(rightText.c_str(), rightText.length(), false); context().drawString(right - rightTextWidth, bottom - unit, rightText.c_str(), rightText.length(), false); }
void BookTextView::saveState() { const ZLTextWordCursor &cursor = textArea().startCursor(); if (myBook.isNull()) { return; } if (!cursor.isNull()) { ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, PARAGRAPH_OPTION_NAME, 0).setValue(cursor.paragraphCursor().index()); ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, WORD_OPTION_NAME, 0).setValue(cursor.elementIndex()); ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, CHAR_OPTION_NAME, 0).setValue(cursor.charIndex()); ZLIntegerOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, POSITION_IN_BUFFER, 0).setValue(myCurrentPointInStack); ZLBooleanOption(ZLCategoryKey::STATE, LAST_STATE_GROUP, STATE_VALID, false).setValue(true); if (myStackChanged) { BooksDB::Instance().saveBookStateStack(*myBook, myPositionStack); myStackChanged = false; } } }