struct BufferView::Private
{
- Private(BufferView & bv) : update_strategy_(FullScreenUpdate),
+ Private(BufferView & bv) :
+ update_strategy_(FullScreenUpdate),
update_flags_(Update::Force),
wh_(0), cursor_(bv),
anchor_pit_(0), anchor_ypos_(0),
Update::flags update_flags_;
///
CoordCache coord_cache_;
+ ///
+ typedef map<MathData const *, MathRow> MathRows;
+ MathRows math_rows_;
/// Estimated average par height for scrollbar.
int wh_;
/// a slice pointing to the start of the row where the cursor
/// is (at last draw time)
CursorSlice current_row_slice_;
- /// a slice pointing to the start of the row where cursor was
- /// at previous draw event
- CursorSlice last_row_slice_;
};
}
+MathRow const & BufferView::mathRow(MathData const * cell) const
+{
+ auto it = d->math_rows_.find(cell);
+ LATTEST(it != d->math_rows_.end());
+ return it->second;
+}
+
+
+void BufferView::setMathRow(MathData const * cell, MathRow const & mrow)
+{
+ d->math_rows_[cell] = mrow;
+}
+
+
Buffer & BufferView::buffer()
{
return buffer_;
return string((flags & Update::FitCursor) ? "FitCursor " : "")
+ ((flags & Update::Force) ? "Force " : "")
+ ((flags & Update::ForceDraw) ? "ForceDraw " : "")
- + ((flags & Update::SinglePar) ? "SinglePar " : "");
+ + ((flags & Update::SinglePar) ? "SinglePar " : "")
+ + ((flags & Update::Decoration) ? "Decoration " : "");
}
}
if (flags == Update::None)
return;
- // SinglePar is ignored for now (this should probably change). We
- // set it ourselves below, at the price of always rebreaking the
- // paragraph at cursor. This can be expensive for large tables.
- flags = flags & ~Update::SinglePar;
+ /* FIXME We would like to avoid doing this here, since it is very
+ * expensive and is called in updateBuffer already. However, even
+ * inserting a plain character can invalidate the overly fragile
+ * tables of child documents built by updateMacros. Some work is
+ * needed to avoid doing that when not necessary.
+ */
+ buffer_.updateMacros();
// First check whether the metrics and inset positions should be updated
if (flags & Update::Force) {
updateMetrics(flags);
}
+ // Detect whether we can only repaint a single paragraph (if we
+ // are not already redrawing all).
+ // We handle this before FitCursor because the later will require
+ // correct metrics at cursor position.
+ if (!(flags & Update::ForceDraw)
+ && (flags & Update::SinglePar)
+ && !singleParUpdate())
+ updateMetrics(flags);
+
// Then make sure that the screen contains the cursor if needed
if (flags & Update::FitCursor) {
if (needsFitCursor()) {
flags = flags & ~Update::FitCursor;
}
- // Finally detect whether we can only repaint a single paragraph
- if (!(flags & Update::ForceDraw)) {
- if (singleParUpdate())
- flags = flags | Update::SinglePar;
- else
- updateMetrics(flags);
- }
-
// Add flags to the the update flags. These will be reset to None
// after the redraw is actually done
d->update_flags_ = d->update_flags_ | flags;
LYXERR(Debug::PAINTING, "Cumulative flags: " << flagsAsString(flags));
// Now compute the update strategy
- // Possibly values in flag are None, Decoration, ForceDraw
+ // Possibly values in flag are None, SinglePar, Decoration, ForceDraw
LATTEST((d->update_flags_ & ~(Update::None | Update::SinglePar
| Update::Decoration | Update::ForceDraw)) == 0);
d->cursor_.setCurrentFont();
// Do not forget to reset the anchor (see #9912)
d->cursor_.resetAnchor();
- processUpdateFlags(Update::FitCursor);
+ processUpdateFlags(Update::Force | Update::FitCursor);
}
return success;
int offset = coordOffset(dit).y_;
int ypos = pm.position() + offset;
Dimension const & row_dim =
- pm.getRow(cs.pos(), dit.boundary()).dimension();
+ pm.getRow(cs.pos(), dit.boundary()).dim();
int scrolled = 0;
if (recenter)
scrolled = scroll(ypos - height_/2);
d->anchor_pit_ = bot_pit;
CursorSlice const & cs = dit.innerTextSlice();
Dimension const & row_dim =
- pm.getRow(cs.pos(), dit.boundary()).dimension();
+ pm.getRow(cs.pos(), dit.boundary()).dim();
if (recenter)
d->anchor_ypos_ = height_/2;
break;
case LFUN_GRAPHICS_UNIFY:
- flag.setEnabled(cur.selection());
+ flag.setEnabled(cur.countInsetsInSelection(GRAPHICS_CODE)>1);
break;
case LFUN_WORD_FINDADV: {
void BufferView::editInset(string const & name, Inset * inset)
{
- d->edited_insets_[name] = inset;
+ if (inset)
+ d->edited_insets_[name] = inset;
+ else
+ d->edited_insets_.erase(name);
}
// without calling recordUndo. Fix this before using
// recordUndoBufferParams().
cur.recordUndoFullBuffer();
- buffer_.params().setBaseClass(argument);
+ buffer_.params().setBaseClass(argument, buffer_.layoutPos());
makeDocumentClass();
dr.screenUpdate(Update::Force);
dr.forceBufferUpdate();
case LFUN_LAYOUT_RELOAD: {
LayoutFileIndex bc = buffer_.params().baseClassID();
LayoutFileList::get().reset(bc);
- buffer_.params().setBaseClass(bc);
+ buffer_.params().setBaseClass(bc, buffer_.layoutPos());
makeDocumentClass();
dr.screenUpdate(Update::Force);
dr.forceBufferUpdate();
// We need to find out if the bibliography information
// has changed. See bug #11055.
// So these should not be references...
- LayoutModuleList const engines = buffer().params().citeEngine();
+ string const engine = buffer().params().citeEngine();
CiteEngineType const enginetype = buffer().params().citeEngineType();
- if (!cur.textUndo())
+ if (!cur.undoAction())
dr.setMessage(_("No further undo information"));
else {
dr.screenUpdate(Update::Force | Update::FitCursor);
dr.forceBufferUpdate();
- if (buffer().params().citeEngine() != engines ||
+ if (buffer().params().citeEngine() != engine ||
buffer().params().citeEngineType() != enginetype)
buffer().invalidateCiteLabels();
}
// We need to find out if the bibliography information
// has changed. See bug #11055.
// So these should not be references...
- LayoutModuleList const engines = buffer().params().citeEngine();
+ string const engine = buffer().params().citeEngine();
CiteEngineType const enginetype = buffer().params().citeEngineType();
- if (!cur.textRedo())
+ if (!cur.redoAction())
dr.setMessage(_("No further redo information"));
else {
dr.screenUpdate(Update::Force | Update::FitCursor);
dr.forceBufferUpdate();
- if (buffer().params().citeEngine() != engines ||
+ if (buffer().params().citeEngine() != engine ||
buffer().params().citeEngineType() != enginetype)
buffer().invalidateCiteLabels();
}
// At least one complete cell is selected and inset is a table.
// Select all cells
cur.idx() = 0;
+ cur.pit() = 0;
cur.pos() = 0;
cur.resetAnchor();
cur.selection(true);
cur.idx() = cur.lastidx();
+ cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
} else {
// select current cell
void BufferView::gotoLabel(docstring const & label)
{
+ FuncRequest action;
+ bool have_inactive = false;
for (Buffer const * buf : buffer().allRelatives()) {
// find label
for (TocItem const & item : *buf->tocBackend().toc("label")) {
- if (label == item.str()) {
+ if (label == item.str() && item.isOutput()) {
lyx::dispatch(item.action());
return;
}
+ // If we find an inactive label, save it for the case
+ // that no active one is there
+ if (label == item.str() && !have_inactive) {
+ have_inactive = true;
+ action = item.action();
+ }
}
}
+ // We only found an inactive label. Go there.
+ if (have_inactive)
+ lyx::dispatch(action);
}
LBUFERR(t);
TextMetricsCache::iterator tmc_it = d->text_metrics_.find(t);
if (tmc_it == d->text_metrics_.end()) {
- tmc_it = d->text_metrics_.insert(
- make_pair(t, TextMetrics(this, const_cast<Text *>(t)))).first;
+ tmc_it = d->text_metrics_.emplace(std::piecewise_construct,
+ std::forward_as_tuple(t),
+ std::forward_as_tuple(this, const_cast<Text *>(t))).first;
}
return tmc_it->second;
}
return false;
bool need_anchor_change = false;
- bool changed = d->cursor_.text()->deleteEmptyParagraphMechanism(cur, old,
+ bool changed = Text::deleteEmptyParagraphMechanism(cur, old,
need_anchor_change);
if (need_anchor_change)
// Clear out the position cache in case of full screen redraw,
d->coord_cache_.clear();
+ d->math_rows_.clear();
// Clear out paragraph metrics to avoid having invalid metrics
// in the cache from paragraphs not relayouted below
}
-void BufferView::insertLyXFile(FileName const & fname)
+void BufferView::insertLyXFile(FileName const & fname, bool const ignorelang)
{
LASSERT(d->cursor_.inTexted(), return);
ErrorList & el = buffer_.errorList("Parse");
// Copy the inserted document error list into the current buffer one.
el = buf.errorList("Parse");
+ ParagraphList & pars = buf.paragraphs();
+ if (ignorelang)
+ // set main language of imported file to context language
+ buf.changeLanguage(buf.language(), d->cursor_.getFont().language());
buffer_.undo().recordUndo(d->cursor_);
- cap::pasteParagraphList(d->cursor_, buf.paragraphs(),
+ cap::pasteParagraphList(d->cursor_, pars,
buf.params().documentClassPtr(), el);
res = _("Document %1$s inserted.");
} else {
void BufferView::caretPosAndHeight(Point & p, int & h) const
{
+ int asc, des;
Cursor const & cur = cursor();
- Font const font = cur.real_current_font;
- frontend::FontMetrics const & fm = theFontMetrics(font);
- int const asc = fm.maxAscent();
- int const des = fm.maxDescent();
+ if (cur.inMathed()) {
+ MathRow const & mrow = mathRow(&cur.cell());
+ asc = mrow.caret_ascent;
+ des = mrow.caret_descent;
+ } else {
+ Font const font = cur.real_current_font;
+ frontend::FontMetrics const & fm = theFontMetrics(font);
+ asc = fm.maxAscent();
+ des = fm.maxDescent();
+ }
h = asc + des;
p = getPos(cur);
p.y_ -= asc;
}
-bool BufferView::hadHorizScrollOffset(Text const * text,
- pit_type pit, pos_type pos) const
-{
- return !d->last_row_slice_.empty()
- && &text->inset() == d->last_row_slice_.inset().asInsetText()
- && pit == d->last_row_slice_.pit()
- && pos == d->last_row_slice_.pos();
-}
-
-
void BufferView::setCurrentRowSlice(CursorSlice const & rowSlice)
{
// nothing to do if the cursor was already on this row
- if (d->current_row_slice_ == rowSlice) {
- d->last_row_slice_ = CursorSlice();
+ if (d->current_row_slice_ == rowSlice)
return;
- }
// if the (previous) current row was scrolled, we have to
// remember it in order to repaint it next time.
- if (d->horiz_scroll_offset_ != 0)
- d->last_row_slice_ = d->current_row_slice_;
- else
- d->last_row_slice_ = CursorSlice();
+ if (d->horiz_scroll_offset_ != 0) {
+ // search the old row in cache and mark it changed
+ for (auto & tm_pair : d->text_metrics_) {
+ if (&tm_pair.first->inset() == rowSlice.inset().asInsetText()) {
+ tm_pair.second.setRowChanged(rowSlice.pit(), rowSlice.pos());
+ // We found it, no need to continue.
+ break;
+ }
+ }
+ }
// Since we changed row, the scroll offset is not valid anymore
d->horiz_scroll_offset_ = 0;
<< d->horiz_scroll_offset_ << " to " << offset);
if (d->update_strategy_ == NoScreenUpdate
- && (offset != d->horiz_scroll_offset_
- || !d->last_row_slice_.empty())) {
+ && offset != d->horiz_scroll_offset_) {
// FIXME: if one uses SingleParUpdate, then home/end
// will not work on long rows. Why?
d->update_strategy_ = FullScreenUpdate;