X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=6089756f9bbae041d28cc8322a1b4ff34712a579;hb=d1e3d75da226311cb290fc4be3686d6deef7b967;hp=09884c6308ce12c8468265b4d3ea376acbd6f534;hpb=83f13982fc22e1c9415211fe029039d8b9ef476d;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 09884c6308..6089756f9b 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -218,7 +218,7 @@ struct BufferView::Private Private(BufferView & bv): wh_(0), cursor_(bv), anchor_pit_(0), anchor_ypos_(0), inlineCompletionUniqueChars_(0), - last_inset_(0), gui_(0) + last_inset_(0), bookmark_edit_position_(0), gui_(0) {} /// @@ -261,6 +261,9 @@ struct BufferView::Private */ Inset * last_inset_; + // cache for id of the paragraph which was edited the last time + int bookmark_edit_position_; + mutable TextMetricsCache text_metrics_; /// Whom to notify. @@ -514,7 +517,10 @@ void BufferView::updateScrollbar() d->scrollbarParameters_.position = 0; // The reference is the top position so we remove one page. - d->scrollbarParameters_.max -= d->scrollbarParameters_.page_step; + if (lyxrc.scroll_below_document) + d->scrollbarParameters_.max -= minVisiblePart(); + else + d->scrollbarParameters_.max -= d->scrollbarParameters_.page_step; } @@ -670,9 +676,19 @@ CursorStatus BufferView::cursorStatus(DocIterator const & dit) const } +void BufferView::bookmarkEditPosition() +{ + // Don't eat cpu time for each keystroke + if (d->cursor_.paragraph().id() == d->bookmark_edit_position_) + return; + saveBookmark(0); + d->bookmark_edit_position_ = d->cursor_.paragraph().id(); +} + + void BufferView::saveBookmark(unsigned int idx) { - // tenatively save bookmark, id and pos will be used to + // tentatively save bookmark, id and pos will be used to // acturately locate a bookmark in a 'live' lyx session. // pit and pos will be updated with bottom level pit/pos // when lyx exits. @@ -713,7 +729,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos, // insets. size_t const n = dit.depth(); for (size_t i = 0; i < n; ++i) - if (dit[i].inset().editable() != Inset::HIGHLY_EDITABLE) { + if (!dit[i].inset().editable()) { dit.resize(i); break; } @@ -774,18 +790,37 @@ int BufferView::workWidth() const } +void BufferView::recenter() +{ + showCursor(d->cursor_, true); +} + + void BufferView::showCursor() { - showCursor(d->cursor_); + showCursor(d->cursor_, false); } -void BufferView::showCursor(DocIterator const & dit) +void BufferView::showCursor(DocIterator const & dit, bool recenter) +{ + if (scrollToCursor(dit, recenter)) + buffer_.changed(); +} + + +void BufferView::scrollToCursor() +{ + scrollToCursor(d->cursor_, false); +} + + +bool BufferView::scrollToCursor(DocIterator const & dit, bool recenter) { // We are not properly started yet, delay until resizing is // done. if (height_ == 0) - return; + return false; LYXERR(Debug::SCROLLING, "recentering!"); @@ -816,16 +851,19 @@ void BufferView::showCursor(DocIterator const & dit) Dimension const & row_dim = pm.getRow(cs.pos(), dit.boundary()).dimension(); int scrolled = 0; - if (ypos - row_dim.ascent() < 0) + if (recenter) + scrolled = scroll(ypos - height_/2); + else if (ypos - row_dim.ascent() < 0) scrolled = scrollUp(- ypos + row_dim.ascent()); else if (ypos + row_dim.descent() > height_) - scrolled = scrollDown(ypos - height_ + row_dim.descent()); + scrolled = scrollDown(ypos - height_ + defaultRowHeight() ); + // else, nothing to do, the cursor is already visible so we just return. if (scrolled != 0) { updateMetrics(); - buffer_.changed(); + return true; } - return; + return false; } // fix inline completion position @@ -841,22 +879,24 @@ void BufferView::showCursor(DocIterator const & dit) Dimension const & row_dim = pm.getRow(cs.pos(), dit.boundary()).dimension(); - if (d->anchor_pit_ == 0) + if (recenter) + d->anchor_ypos_ = height_/2; + else if (d->anchor_pit_ == 0) d->anchor_ypos_ = offset + pm.ascent(); else if (d->anchor_pit_ == max_pit) d->anchor_ypos_ = height_ - offset - row_dim.descent(); + else if (offset > height_) + d->anchor_ypos_ = height_ - offset - defaultRowHeight(); else - d->anchor_ypos_ = defaultRowHeight() * 2 - offset - row_dim.descent(); + d->anchor_ypos_ = defaultRowHeight() * 2; updateMetrics(); - buffer_.changed(); + return true; } -FuncStatus BufferView::getStatus(FuncRequest const & cmd) +bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) { - FuncStatus flag; - Cursor & cur = d->cursor_; switch (cmd.action) { @@ -874,6 +914,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) // FIXME: Actually, these LFUNS should be moved to Text flag.setEnabled(cur.inTexted()); break; + case LFUN_FONT_STATE: case LFUN_LABEL_INSERT: case LFUN_INFO_INSERT: @@ -888,6 +929,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_MARK_ON: case LFUN_MARK_TOGGLE: case LFUN_SCREEN_RECENTER: + case LFUN_SCREEN_SHOW_CURSOR: case LFUN_BIBTEX_DATABASE_ADD: case LFUN_BIBTEX_DATABASE_DEL: case LFUN_NOTES_MUTATE: @@ -903,19 +945,17 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_COPY_LABEL_AS_REF: { // if there is an inset at cursor, see whether it - // handles the lfun, other start from scratch + // handles the lfun Inset * inset = cur.nextInset(); if (!inset || !inset->getStatus(cur, cmd, flag)) flag.setEnabled(false); break; } - case LFUN_NEXT_INSET_TOGGLE: case LFUN_NEXT_INSET_MODIFY: { // this is the real function we want to invoke FuncRequest tmpcmd = cmd; - tmpcmd.action = (cmd.action == LFUN_NEXT_INSET_TOGGLE) - ? LFUN_INSET_TOGGLE : LFUN_INSET_MODIFY; + tmpcmd.action = LFUN_INSET_MODIFY; // if there is an inset at cursor, see whether it // handles the lfun, other start from scratch Inset * inset = cur.nextInset(); @@ -942,6 +982,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_CHANGES_MERGE: case LFUN_CHANGE_NEXT: + case LFUN_CHANGE_PREVIOUS: case LFUN_ALL_CHANGES_ACCEPT: case LFUN_ALL_CHANGES_REJECT: // TODO: context-sensitive enabling of LFUNs @@ -976,60 +1017,19 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) flag.setEnabled(cur.inset().allowParagraphCustomization(cur.idx())); break; - case LFUN_INSET_SETTINGS: { - InsetCode code = cur.inset().lyxCode(); - if (cmd.getArg(0) == insetName(code)) { - flag.setEnabled(true); - break; - } - bool enable = false; - InsetCode next_code = cur.nextInset() - ? cur.nextInset()->lyxCode() : NO_CODE; - //FIXME: remove these special cases: - switch (next_code) { - case TABULAR_CODE: - case ERT_CODE: - case FLOAT_CODE: - case WRAP_CODE: - case NOTE_CODE: - case BRANCH_CODE: - case BOX_CODE: - case LISTINGS_CODE: - enable = (cmd.argument().empty() || - cmd.getArg(0) == insetName(next_code)); - break; - default: - break; - } - flag.setEnabled(enable); - break; - } - case LFUN_DIALOG_SHOW_NEW_INSET: + if (cur.inset().lyxCode() == CAPTION_CODE) + return cur.inset().getStatus(cur, cmd, flag); flag.setEnabled(cur.inset().lyxCode() != ERT_CODE && cur.inset().lyxCode() != LISTINGS_CODE); - if (cur.inset().lyxCode() == CAPTION_CODE) { - FuncStatus flag; - if (cur.inset().getStatus(cur, cmd, flag)) - return flag; - } break; - case LFUN_BRANCH_ACTIVATE: - case LFUN_BRANCH_DEACTIVATE: { - bool enable = false; - docstring const branchName = cmd.argument(); - if (!branchName.empty()) - enable = buffer_.params().branchlist().find(branchName); - flag.setEnabled(enable); - break; - } - default: flag.setEnabled(false); + return false; } - return flag; + return true; } @@ -1078,7 +1078,7 @@ bool BufferView::dispatch(FuncRequest const & cmd) docstring label = cmd.argument(); if (label.empty()) { InsetRef * inset = - getInsetByCode(d->cursor_, REF_CODE); + getInsetByCode(cur, REF_CODE); if (inset) { label = inset->getParam("reference"); // persistent=false: use temp_bookmark @@ -1186,9 +1186,15 @@ bool BufferView::dispatch(FuncRequest const & cmd) // FIXME: Move this LFUN to Buffer so that we don't have to do this: processUpdateFlags(Update::Force | Update::FitCursor); break; + + case LFUN_CHANGE_PREVIOUS: + findPreviousChange(this); + // FIXME: Move this LFUN to Buffer so that we don't have to do this: + processUpdateFlags(Update::Force | Update::FitCursor); + break; case LFUN_CHANGES_MERGE: - if (findNextChange(this)) { + if (findNextChange(this) || findPreviousChange(this)) { processUpdateFlags(Update::Force | Update::FitCursor); showDialog("changes"); } @@ -1196,23 +1202,23 @@ bool BufferView::dispatch(FuncRequest const & cmd) case LFUN_ALL_CHANGES_ACCEPT: // select complete document - d->cursor_.reset(buffer_.inset()); - d->cursor_.selHandle(true); - buffer_.text().cursorBottom(d->cursor_); + cur.reset(buffer_.inset()); + cur.selHandle(true); + buffer_.text().cursorBottom(cur); // accept everything in a single step to support atomic undo - buffer_.text().acceptOrRejectChanges(d->cursor_, Text::ACCEPT); + buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: processUpdateFlags(Update::Force | Update::FitCursor); break; case LFUN_ALL_CHANGES_REJECT: // select complete document - d->cursor_.reset(buffer_.inset()); - d->cursor_.selHandle(true); - buffer_.text().cursorBottom(d->cursor_); + cur.reset(buffer_.inset()); + cur.selHandle(true); + buffer_.text().cursorBottom(cur); // reject everything in a single step to support atomic undo // Note: reject does not work recursively; the user may have to repeat the operation - buffer_.text().acceptOrRejectChanges(d->cursor_, Text::REJECT); + buffer_.text().acceptOrRejectChanges(cur, Text::REJECT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: processUpdateFlags(Update::Force | Update::FitCursor); break; @@ -1255,19 +1261,17 @@ bool BufferView::dispatch(FuncRequest const & cmd) case LFUN_MARK_OFF: cur.clearSelection(); - cur.resetAnchor(); cur.message(from_utf8(N_("Mark off"))); break; case LFUN_MARK_ON: cur.clearSelection(); cur.setMark(true); - cur.resetAnchor(); cur.message(from_utf8(N_("Mark on"))); break; case LFUN_MARK_TOGGLE: - cur.clearSelection(); + cur.setSelection(false); if (cur.mark()) { cur.setMark(false); cur.message(from_utf8(N_("Mark removed"))); @@ -1278,12 +1282,16 @@ bool BufferView::dispatch(FuncRequest const & cmd) cur.resetAnchor(); break; - case LFUN_SCREEN_RECENTER: + case LFUN_SCREEN_SHOW_CURSOR: showCursor(); break; + + case LFUN_SCREEN_RECENTER: + recenter(); + break; case LFUN_BIBTEX_DATABASE_ADD: { - Cursor tmpcur = d->cursor_; + Cursor tmpcur = cur; findInset(tmpcur, BIBTEX_CODE, false); InsetBibtex * inset = getInsetByCode(tmpcur, BIBTEX_CODE); @@ -1295,7 +1303,7 @@ bool BufferView::dispatch(FuncRequest const & cmd) } case LFUN_BIBTEX_DATABASE_DEL: { - Cursor tmpcur = d->cursor_; + Cursor tmpcur = cur; findInset(tmpcur, BIBTEX_CODE, false); InsetBibtex * inset = getInsetByCode(tmpcur, BIBTEX_CODE); @@ -1363,35 +1371,6 @@ bool BufferView::dispatch(FuncRequest const & cmd) processUpdateFlags(Update::SinglePar | Update::FitCursor); break; } - case LFUN_NEXT_INSET_TOGGLE: { - // create the the real function we want to invoke - FuncRequest tmpcmd = cmd; - tmpcmd.action = LFUN_INSET_TOGGLE; - // if there is an inset at cursor, see whether it - // wants to toggle. - Inset * inset = cur.nextInset(); - if (inset) { - if (inset->isActive()) { - Cursor tmpcur = cur; - tmpcur.pushBackward(*inset); - inset->dispatch(tmpcur, tmpcmd); - if (tmpcur.result().dispatched()) - cur.dispatched(); - } else - inset->dispatch(cur, tmpcmd); - } - // if it did not work, try the underlying inset. - if (!inset || !cur.result().dispatched()) - cur.dispatch(tmpcmd); - - if (!cur.result().dispatched()) - // It did not work too; no action needed. - break; - cur.clearSelection(); - processUpdateFlags(Update::SinglePar | Update::FitCursor); - break; - } - case LFUN_NEXT_INSET_MODIFY: { // create the the real function we want to invoke FuncRequest tmpcmd = cmd; @@ -1431,12 +1410,17 @@ bool BufferView::dispatch(FuncRequest const & cmd) p = Point(0, 0); if (cmd.action == LFUN_SCREEN_DOWN && scrolled < height_) p = Point(width_, height_); + Cursor old = cur; + bool const in_texted = cur.inTexted(); cur.reset(buffer_.inset()); updateMetrics(); buffer_.changed(); d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_); //FIXME: what to do with cur.x_target()? + bool update = in_texted && cur.bv().checkDepm(cur, old); cur.finishUndo(); + if (update) + processUpdateFlags(Update::Force | Update::FitCursor); break; } @@ -1478,12 +1462,6 @@ bool BufferView::dispatch(FuncRequest const & cmd) break; } - case LFUN_BRANCH_ACTIVATE: - case LFUN_BRANCH_DEACTIVATE: - buffer_.dispatch(cmd); - processUpdateFlags(Update::Force); - break; - // This could be rewriten using some command like forall // once the insets refactoring is done. case LFUN_NOTES_MUTATE: { @@ -1722,6 +1700,12 @@ void BufferView::lfunScroll(FuncRequest const & cmd) } +int BufferView::minVisiblePart() +{ + return 2 * defaultRowHeight(); +} + + int BufferView::scroll(int y) { if (y > 0) @@ -1736,10 +1720,12 @@ int BufferView::scrollDown(int offset) { Text * text = &buffer_.text(); TextMetrics & tm = d->text_metrics_[text]; - int ymax = height_ + offset; + int const ymax = height_ + offset; while (true) { pair last = tm.last(); int bottom_pos = last.second->position() + last.second->descent(); + if (lyxrc.scroll_below_document) + bottom_pos += height_ - minVisiblePart(); if (last.first + 1 == int(text->paragraphs().size())) { if (bottom_pos <= height_) return 0; @@ -2247,6 +2233,29 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const } +void BufferView::cursorPosAndHeight(Point & p, int & h) const +{ + Cursor const & cur = cursor(); + Font const font = cur.getFont(); + frontend::FontMetrics const & fm = theFontMetrics(font); + int const asc = fm.maxAscent(); + int const des = fm.maxDescent(); + h = asc + des; + p = getPos(cur, cur.boundary()); + p.y_ -= asc; +} + + +bool BufferView::cursorInView(Point const & p, int h) const +{ + Cursor const & cur = cursor(); + // does the cursor touch the screen ? + if (p.y_ + h < 0 || p.y_ >= workHeight() || !paragraphVisible(cur)) + return false; + return true; +} + + void BufferView::draw(frontend::Painter & pain) { if (height_ == 0 || width_ == 0) @@ -2436,6 +2445,8 @@ bool samePar(DocIterator const & a, DocIterator const & b) return true; if (a.empty() || b.empty()) return false; + if (a.depth() != b.depth()) + return false; return &a.innerParagraph() == &b.innerParagraph(); }