Abdelrazak Younes wrote:
Hello,
Here is the first draft of the model/view separation of the Paragraph
class. It is mostly working already execept for Copy&Paste and
MultipleView.
I've solve the C&P issue and many others. In single window mode, the
attached patch is very stable, I did extensive testing but could not
make it crash (including with DEPM action triggered). There's no
painting problem either. From this point I'd welcome any additional
testing. But I really think it is ready for inclusion.
So, objections?
In multiple view mode, there's still one problem related to
LyXText::max_width_ which is still BufferView dependant. I can solve it
after committing this patch or before, as you wish.
Abdel.
Index: BufferView.C
===================================================================
--- BufferView.C (revision 16395)
+++ BufferView.C (working copy)
@@ -420,13 +420,14 @@
// estimated average paragraph height:
if (wh_ == 0)
wh_ = height_ / 4;
- int h = t.getPar(anchor_ref_).height();
+ int h = text_metrics_[&t][anchor_ref_].height();
+
// Normalize anchor/offset (MV):
while (offset_ref_ > h && anchor_ref_ < parsize) {
anchor_ref_++;
offset_ref_ -= h;
- h = t.getPar(anchor_ref_).height();
+ h = text_metrics_[&t][anchor_ref_].height();
}
// Look at paragraph heights on-screen
int sumh = 0;
@@ -434,7 +435,7 @@
for (pit_type pit = anchor_ref_; pit <= parsize; ++pit) {
if (sumh > height_)
break;
- int const h2 = t.getPar(pit).height();
+ int const h2 = text_metrics_[&t][pit].height();
sumh += h2;
nh++;
}
@@ -473,8 +474,8 @@
anchor_ref_ = int(bar * t.paragraphs().size());
if (anchor_ref_ > int(t.paragraphs().size()) - 1)
anchor_ref_ = int(t.paragraphs().size()) - 1;
- t.redoParagraph(*this, anchor_ref_);
- int const h = t.getPar(anchor_ref_).height();
+ redoParagraph(&t, anchor_ref_);
+ int const h = text_metrics_[&t][anchor_ref_].height();
offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h);
updateMetrics(false);
}
@@ -572,11 +573,11 @@
{
CursorSlice & bot = cursor_.bottom();
pit_type const pit = bot.pit();
- bot.text()->redoParagraph(*this, pit);
- Paragraph const & par = bot.text()->paragraphs()[pit];
+ redoParagraph(bot.text(), pit);
+ ParagraphMetrics const & pm = text_metrics_[bot.text()][pit];
anchor_ref_ = pit;
offset_ref_ = bv_funcs::coordOffset(*this, cursor_,
cursor_.boundary()).y_
- + par.ascent() - height_ / 2;
+ + pm.ascent() - height_ / 2;
}
@@ -1190,6 +1191,31 @@
}
+ParagraphMetrics const & BufferView::parMetrics(LyXText const * t,
+ pit_type pit) const
+{
+ return parMetrics(t, pit, true);
+}
+
+
+ParagraphMetrics & BufferView::parMetrics(LyXText const * t,
+ pit_type pit, bool redo) const
+{
+ TextMetricsCache::iterator tmc_it = text_metrics_.find(t);
+ if (tmc_it == text_metrics_.end()) {
+ tmc_it = text_metrics_.insert(make_pair(t,
ParMetricsCache())).first;
+ }
+ ParMetricsCache::iterator pmc_it = tmc_it->second.find(pit);
+ if (pmc_it == tmc_it->second.end()) {
+ pmc_it = tmc_it->second.insert(make_pair(pit,
ParagraphMetrics(t->getPar(pit)))).first;
+ }
+ if (pmc_it->second.rows().empty() && redo) {
+ redoParagraph(const_cast<LyXText *>(t), pit);
+ }
+ return pmc_it->second;
+}
+
+
int BufferView::workHeight() const
{
return height_;
@@ -1273,10 +1299,6 @@
void BufferView::updateMetrics(bool singlepar)
{
- // Clear out the position cache in case of full screen redraw.
- if (!singlepar)
- coord_cache_.clear();
-
LyXText & buftext = buffer_->text();
pit_type size = int(buftext.paragraphs().size());
@@ -1295,23 +1317,29 @@
// (if this paragraph contains insets etc., rebreaking will
// recursively descend)
if (!singlepar || pit == cursor_.bottom().pit())
- buftext.redoParagraph(*this, pit);
- int y0 = buftext.getPar(pit).ascent() - offset_ref_;
+ if (redoParagraph(&buftext, pit))
+ singlepar = false;
+
+ // Clear out the position cache in case of full screen redraw.
+ if (!singlepar)
+ coord_cache_.clear();
+ int y0 = text_metrics_[&buftext][pit].ascent() - offset_ref_;
+
// Redo paragraphs above anchor if necessary; again, in Single Par
// mode, only if we encounter the (main text) one having the cursor.
int y1 = y0;
while (y1 > 0 && pit1 > 0) {
- y1 -= buftext.getPar(pit1).ascent();
+ y1 -= text_metrics_[&buftext][pit1].ascent();
--pit1;
if (!singlepar || pit1 == cursor_.bottom().pit())
- buftext.redoParagraph(*this, pit1);
- y1 -= buftext.getPar(pit1).descent();
+ redoParagraph(&buftext, pit1);
+ y1 -= text_metrics_[&buftext][pit1].descent();
}
// Take care of ascent of first line
- y1 -= buftext.getPar(pit1).ascent();
+ y1 -= text_metrics_[&buftext][pit1].ascent();
// Normalize anchor for next time
anchor_ref_ = pit1;
@@ -1328,30 +1356,30 @@
// only the one containing the cursor if encountered.
int y2 = y0;
while (y2 < height_ && pit2 < int(npit) - 1) {
- y2 += buftext.getPar(pit2).descent();
+ y2 += text_metrics_[&buftext][pit2].descent();
++pit2;
if (!singlepar || pit2 == cursor_.bottom().pit())
- buftext.redoParagraph(*this, pit2);
- y2 += buftext.getPar(pit2).ascent();
+ redoParagraph(&buftext, pit2);
+ y2 += text_metrics_[&buftext][pit2].ascent();
}
// Take care of descent of last line
- y2 += buftext.getPar(pit2).descent();
+ y2 += text_metrics_[&buftext][pit2].descent();
// The coordinates of all these paragraphs are correct, cache them
int y = y1;
CoordCache::InnerParPosCache & parPos = coord_cache_.parPos()[&buftext];
for (pit_type pit = pit1; pit <= pit2; ++pit) {
- Paragraph const & par = buftext.getPar(pit);
- y += par.ascent();
+ ParagraphMetrics const & pm = text_metrics_[&buftext][pit];
+ y += pm.ascent();
parPos[pit] = Point(0, y);
if (singlepar && pit == cursor_.bottom().pit()) {
// In Single Paragraph mode, collect here the
// y1 and y2 of the (one) paragraph the cursor is in
- y1 = y - par.ascent();
- y2 = y + par.descent();
+ y1 = y - pm.ascent();
+ y2 = y + pm.descent();
}
- y += par.descent();
+ y += pm.descent();
}
if (singlepar) {
@@ -1450,4 +1478,83 @@
}
+bool BufferView::redoParagraph(LyXText * text, pit_type const pit) const
+{
+ // remove rows of paragraph, keep track of height changes
+ Paragraph & par = text->getPar(pit);
+ ParagraphMetrics pm(par);
+
+ bool changed = false;
+
+ // FIXME: this has nothing to do here and is the reason why text is not
+ // const.
+ if (par.checkBiblio(buffer_->params().trackChanges))
+ const_cast<LCursor &>(cursor()).posRight();
+
+ // Optimisation: this is used in the next two loops
+ // so better to calculate that once here.
+ int const right_margin = (text == &buffer_->text())?
+ pm.rightMargin(*buffer_) : 0;
+
+ // redo insets
+ // FIXME: We should always use getFont(), see documentation of
+ // noFontChange() in insetbase.h.
+ LyXFont const bufferfont = buffer_->params().getFont();
+ InsetList::const_iterator ii = par.insetlist.begin();
+ InsetList::const_iterator iend = par.insetlist.end();
+ for (; ii != iend; ++ii) {
+ Dimension dim;
+ int const w = text->maxwidth_ - text->leftMargin(*buffer_, pit,
ii->pos)
+ - right_margin;
+ LyXFont const & font = ii->inset->noFontChange() ?
+ bufferfont : text->getFont(*buffer_, par, ii->pos);
+ // FIXME: MetricsInfo should only need a const BufferView.
+ MetricsInfo mi(const_cast<BufferView *>(this), font, w);
+ changed |= ii->inset->metrics(mi, dim);
+ }
+
+ // rebreak the paragraph
+ pm.rows().clear();
+
+ par.setBeginOfBody();
+ pos_type z = 0;
+ do {
+ Row row(z);
+ text->rowBreakPoint(*buffer_, right_margin, pit, row);
+ text->setRowWidth(*buffer_, right_margin, pit, row);
+ text->setHeightOfRow(*this, pit, row);
+ pm.rows().push_back(row);
+ pm.dim().wid = std::max(pm.dim().wid, row.width());
+ pm.dim().des += row.height();
+ z = row.endpos();
+ } while (z < par.size());
+
+ // Make sure that if a par ends in newline, there is one more row
+ // under it
+ // FIXME this is a dirty trick. Now the _same_ position in the
+ // paragraph occurs in _two_ different rows, and has two different
+ // display positions, leading to weird behaviour when moving up/down.
+ if (z > 0 && par.isNewline(z - 1)) {
+ Row row(z - 1);
+ row.endpos(z - 1);
+ text->setRowWidth(*buffer_, right_margin, pit, row);
+ text->setHeightOfRow(*this, pit, row);
+ pm.rows().push_back(row);
+ pm.dim().des += row.height();
+ }
+
+ pm.dim().asc += pm.rows()[0].ascent();
+ pm.dim().des -= pm.rows()[0].ascent();
+
+ // IMPORTANT NOTE: We pass 'false' explicitely in order to not call
+ // redoParagraph() recursively inside parMetrics.
+ Dimension old_dim = parMetrics(text, pit, false).dim();
+
+ changed |= old_dim.height() != pm.dim().height();
+
+ text_metrics_[text][pit] = pm;
+
+ return changed;
+}
+
} // namespace lyx
Index: BufferView.h
===================================================================
--- BufferView.h (revision 16395)
+++ BufferView.h (working copy)
@@ -42,6 +42,7 @@
class LCursor;
class LyXText;
class ParIterator;
+class ParagraphMetrics;
class ViewMetricsInfo;
/// Scrollbar Parameters.
@@ -205,6 +206,15 @@
void updateMetrics(bool singlepar = false);
///
+ ParagraphMetrics const & parMetrics(LyXText const *, pit_type) const;
+ ParagraphMetrics & parMetrics(LyXText const *, pit_type, bool redo)
const;
+
+ /// Rebreaks the given paragraph.
+ /// \retval true if a full screen redraw is needed.
+ /// \retval false if a single paragraph redraw is enough.
+ bool redoParagraph(LyXText * text, pit_type const pit) const;
+
+ ///
CoordCache & coordCache() {
return coord_cache_;
}
@@ -281,6 +291,12 @@
/// last visited inset (kept to send setMouseHover(false) )
InsetBase * last_inset_;
+
+ /// A map from paragraph index number to paragraph metrics
+ typedef std::map<pit_type, ParagraphMetrics> ParMetricsCache;
+ /// A map from a LyXText to the map of paragraphs metrics
+ typedef std::map<LyXText const *, ParMetricsCache> TextMetricsCache;
+ mutable TextMetricsCache text_metrics_;
};
Index: bufferview_funcs.C
===================================================================
--- bufferview_funcs.C (revision 16395)
+++ bufferview_funcs.C (working copy)
@@ -176,12 +176,9 @@
// Add contribution of initial rows of outermost paragraph
CursorSlice const & sl = dit[0];
- Paragraph const & par = sl.text()->getPar(sl.pit());
- if (par.rows().empty())
- // FIXME: The special case below happens for empty paragraph
creation
- const_cast<LyXText
*>(sl.text())->redoParagraph(const_cast<BufferView &>(bv), sl.pit());
- BOOST_ASSERT(!par.rows().empty());
- y -= par.rows()[0].ascent();
+ ParagraphMetrics const & pm = bv.parMetrics(sl.text(), sl.pit());
+ BOOST_ASSERT(!pm.rows().empty());
+ y -= pm.rows()[0].ascent();
#if 1
size_t rend;
if (sl.pos() > 0 && dit.depth() == 1) {
@@ -189,16 +186,16 @@
if (pos && boundary)
--pos;
// lyxerr << "coordOffset: boundary:" << boundary << " depth:" <<
dit.depth() << " pos:" << pos << " sl.pos:" << sl.pos() << std::endl;
- rend = par.pos2row(pos);
+ rend = pm.pos2row(pos);
} else
- rend = par.pos2row(sl.pos());
+ rend = pm.pos2row(sl.pos());
#else
- size_t rend = par.pos2row(sl.pos());
+ size_t rend = pm.pos2row(sl.pos());
#endif
for (size_t rit = 0; rit != rend; ++rit)
- y += par.rows()[rit].height();
- y += par.rows()[rend].ascent();
- x += dit.bottom().text()->cursorX(*bv.buffer(), dit.bottom(), boundary
&& dit.depth() == 1);
+ y += pm.rows()[rit].height();
+ y += pm.rows()[rend].ascent();
+ x += dit.bottom().text()->cursorX(bv, dit.bottom(), boundary &&
dit.depth() == 1);
return Point(x, y);
}
Index: cursor.C
===================================================================
--- cursor.C (revision 16395)
+++ cursor.C (working copy)
@@ -403,17 +403,11 @@
}
-Row & LCursor::textRow()
-{
- BOOST_ASSERT(!paragraph().rows().empty());
- return paragraph().getRow(pos(), boundary());
-}
-
-
Row const & LCursor::textRow() const
{
- BOOST_ASSERT(!paragraph().rows().empty());
- return paragraph().getRow(pos(), boundary());
+ ParagraphMetrics const & pm = bv().parMetrics(text(), pit());
+ BOOST_ASSERT(!pm.rows().empty());
+ return pm.getRow(pos(), boundary());
}
Index: cursor.h
===================================================================
--- cursor.h (revision 16395)
+++ cursor.h (working copy)
@@ -104,7 +104,7 @@
/// returns x,y position
void getPos(int & x, int & y) const;
/// the row in the paragraph we're in
- Row & textRow();
+ //Row & textRow();
/// the row in the paragraph we're in
Row const & textRow() const;
Index: CutAndPaste.C
===================================================================
--- CutAndPaste.C (revision 16395)
+++ CutAndPaste.C (working copy)
@@ -627,7 +627,7 @@
textclass, errorList);
updateLabels(cur.buffer());
cur.clearSelection();
- text->setCursor(cur, ppp.first, ppp.second);
+ text->setCursor(cur.top(), ppp.first, ppp.second);
}
// mathed is handled in InsetMathNest/InsetMathGrid
Index: frontends/qt4/GuiWorkArea.C
===================================================================
--- frontends/qt4/GuiWorkArea.C (revision 16395)
+++ frontends/qt4/GuiWorkArea.C (working copy)
@@ -268,32 +268,12 @@
// in BufferList that could be connected to the different tabbars.
lyx_view_.updateTab();
- //FIXME: Use case: Two windows share the same buffer.
- // The first window is resize. This modify the inner Buffer
- // structure because Paragraph has a notion of line break and
- // thus line width (this is very bad!).
- // When switching to the other window which does not have the
- // same size, LyX crashes because the line break is not adapted
- // the this BufferView width.
- // The following line fix the crash by resizing the BufferView
- // on a focusInEvent(). That is not a good fix but it is a fix
- // nevertheless. The bad side effect is that when the two
- // BufferViews show the same portion of the Buffer, the second
- // BufferView will show the same line breaks as the first one;
- // even though those line breaks are not adapted to the second
- // BufferView width... such is life!
- resizeBufferView();
-
startBlinkingCursor();
}
void GuiWorkArea::focusOutEvent(QFocusEvent * /*event*/)
{
- // No need to do anything if we didn't change views...
- if (&lyx_view_ == theApp()->currentView())
- return;
-
stopBlinkingCursor();
}
Index: insets/insettabular.C
===================================================================
--- insets/insettabular.C (revision 16395)
+++ insets/insettabular.C (working copy)
@@ -603,10 +603,12 @@
cur.idx() = tabular.getCellAbove(cur.idx());
cur.pit() = cur.lastpit();
LyXText const * text =
cell(cur.idx())->getText(0);
+ ParagraphMetrics const & pm =
+ cur.bv().parMetrics(text,
cur.lastpit());
cur.pos() = text->x2pos(
cur.bv(),
cur.pit(),
-
text->paragraphs().back().rows().size()-1,
+ pm.rows().size()-1,
cur.targetX());
}
if (sl == cur.top()) {
Index: insets/insettext.C
===================================================================
--- insets/insettext.C (revision 16395)
+++ insets/insettext.C (working copy)
@@ -184,7 +184,6 @@
void InsetText::draw(PainterInfo & pi, int x, int y) const
{
- BOOST_ASSERT(!text_.paragraphs().front().rows().empty());
// update our idea of where we are
setPosCache(pi, x, y);
@@ -340,8 +339,8 @@
void InsetText::cursorPos(BufferView const & bv,
CursorSlice const & sl, bool boundary, int & x, int & y) const
{
- x = text_.cursorX(*bv.buffer(), sl, boundary) + border_;
- y = text_.cursorY(sl, boundary);
+ x = text_.cursorX(bv, sl, boundary) + border_;
+ y = text_.cursorY(bv, sl, boundary);
}
Index: lyxtext.h
===================================================================
--- lyxtext.h (revision 16395)
+++ lyxtext.h (working copy)
@@ -96,11 +96,6 @@
/// Set font over selection paragraphs and rebreak.
void setFont(LCursor & cur, LyXFont const &, bool toggleall = false);
- /// Rebreaks the given paragraph.
- /// \retval true if a full screen redraw is needed.
- /// \retval false if a single paragraph redraw is enough.
- bool redoParagraph(BufferView &, pit_type pit);
-
/// returns pos in given par at given x coord
pos_type x2pos(BufferView const &, pit_type pit, int row, int x) const;
int pos2x(pit_type pit, pos_type pos) const;
@@ -153,8 +148,8 @@
/** returns the column near the specified x-coordinate of the row
x is set to the real beginning of this column
*/
- pos_type getColumnNearX(BufferView const & bv, pit_type pit,
- Row const & row, int & x, bool & boundary) const;
+ pos_type getColumnNearX(BufferView const & bv, int right_margin,
+ pit_type pit, Row const & row, int & x, bool & boundary) const;
/** Find the word under \c from in the relative location
* defined by \c word_location.
@@ -304,12 +299,12 @@
int leftMargin(Buffer const &, pit_type pit, pos_type pos) const;
int leftMargin(Buffer const &, pit_type pit) const;
///
- int rightMargin(Buffer const &, Paragraph const & par) const;
+ int rightMargin(Buffer const &, ParagraphMetrics const & pm) const;
/** this calculates the specified parameters. needed when setting
* the cursor and when creating a visible row */
- RowMetrics computeRowMetrics(Buffer const &, pit_type pit,
- Row const & row) const;
+ RowMetrics computeRowMetrics(Buffer const &, int right_margin,
+ pit_type pit, Row const & row) const;
/// access to our paragraphs
ParagraphList const & paragraphs() const { return pars_; }
@@ -317,9 +312,6 @@
/// return true if this is the main text
bool isMainText(Buffer const &) const;
- /// return first row of text
- Row const & firstRow() const;
-
/// is this row the last in the text?
bool isLastRow(pit_type pit, Row const & row) const;
/// is this row the first in the text?
@@ -344,14 +336,26 @@
///
int descent() const;
///
- int cursorX(Buffer const &, CursorSlice const & cursor,
+ int cursorX(BufferView const &, CursorSlice const & cursor,
bool boundary) const;
///
- int cursorY(CursorSlice const & cursor, bool boundary) const;
+ int cursorY(BufferView const & bv, CursorSlice const & cursor,
+ bool boundary) const;
/// delete double space or empty paragraphs around old cursor
bool deleteEmptyParagraphMechanism(LCursor & cur, LCursor & old);
+ /// sets row.end to the pos value *after* which a row should break.
+ /// for example, the pos after which isNewLine(pos) == true
+ void rowBreakPoint(Buffer const &, int right_margin, pit_type pit,
+ Row & row) const;
+ /// sets row.width to the minimum space a row needs on the screen in
pixel
+ void setRowWidth(Buffer const &, int right_margin, pit_type pit,
+ Row & row) const;
+
+ /// Calculate and set the height of the row
+ void setHeightOfRow(BufferView const &, pit_type, Row & row);
+
public:
///
Dimension dim_;
@@ -380,9 +384,6 @@
/// change on pit
pit_type undoSpan(pit_type pit);
- /// Calculate and set the height of the row
- void setHeightOfRow(BufferView const &, pit_type, Row & row);
-
// fix the cursor `cur' after a characters has been deleted at `where'
// position. Called by deleteEmptyParagraphMechanism
void fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where);
@@ -398,12 +399,6 @@
///
void deleteLineForward(LCursor & cur);
- /// sets row.end to the pos value *after* which a row should break.
- /// for example, the pos after which isNewLine(pos) == true
- void rowBreakPoint(Buffer const &, int right_margin, pit_type pit,
- Row & row) const;
- /// sets row.width to the minimum space a row needs on the screen in
pixel
- void setRowWidth(Buffer const &, pit_type pit, Row & row) const;
/// the minimum space a manual label needs on the screen in pixels
int labelFill(Buffer const &, Paragraph const & par, Row const & row)
const;
/// FIXME
Index: paragraph.C
===================================================================
--- paragraph.C (revision 16395)
+++ paragraph.C (working copy)
@@ -34,10 +34,15 @@
#include "outputparams.h"
#include "paragraph_funcs.h"
#include "ParagraphList_fwd.h"
+
+#include "rowpainter.h"
+
#include "sgml.h"
#include "texrow.h"
#include "vspace.h"
+#include "frontends/FontMetrics.h"
+
#include "insets/insetbibitem.h"
#include "insets/insetoptarg.h"
@@ -69,6 +74,11 @@
using std::ostringstream;
+ParagraphMetrics::ParagraphMetrics(Paragraph const & par): par_(&par)
+{
+}
+
+
Row & ParagraphMetrics::getRow(pos_type pos, bool boundary)
{
BOOST_ASSERT(!rows().empty());
@@ -130,7 +140,23 @@
}
}
+int ParagraphMetrics::rightMargin(Buffer const & buffer) const
+{
+ BufferParams const & params = buffer.params();
+ LyXTextClass const & tclass = params.getLyXTextClass();
+ docstring trmarg = from_utf8(tclass.rightmargin());
+ docstring lrmarg = from_utf8(par_->layout()->rightmargin);
+ frontend::FontMetrics const & fm = theFontMetrics(params.getFont());
+ int const r_margin =
+ lyx::rightMargin()
+ + fm.signedWidth(trmarg)
+ + fm.signedWidth(lrmarg)
+ * 4 / (par_->getDepth() + 4);
+ return r_margin;
+}
+
+
Paragraph::Paragraph()
: begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
{
@@ -140,8 +166,7 @@
Paragraph::Paragraph(Paragraph const & par)
- : ParagraphMetrics(par),
- itemdepth(par.itemdepth), insetlist(par.insetlist),
+ : itemdepth(par.itemdepth), insetlist(par.insetlist),
layout_(par.layout_),
text_(par.text_), begin_of_body_(par.begin_of_body_),
pimpl_(new Paragraph::Pimpl(*par.pimpl_, this))
@@ -172,8 +197,6 @@
delete pimpl_;
pimpl_ = new Pimpl(*par.pimpl_, this);
-
- ParagraphMetrics::operator=(par);
}
return *this;
}
@@ -1666,4 +1689,25 @@
}
+bool Paragraph::checkBiblio(bool track_changes)
+{
+ // Add bibitem insets if necessary
+ if (layout()->labeltype != LABEL_BIBLIO)
+ return false;
+
+ bool hasbibitem = !insetlist.empty()
+ // Insist on it being in pos 0
+ && getChar(0) == Paragraph::META_INSET
+ && insetlist.begin()->inset->lyxCode() ==
InsetBase::BIBITEM_CODE;
+
+ if (hasbibitem)
+ return false;
+
+ InsetBibitem * inset(new InsetBibitem(InsetCommandParams("bibitem")));
+ insertInset(0, static_cast<InsetBase *>(inset),
+ Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
+
+ return true;
+}
+
} // namespace lyx
Index: paragraph.h
===================================================================
--- paragraph.h (revision 16395)
+++ paragraph.h (working copy)
@@ -58,53 +58,11 @@
pos_type first, last;
};
-/// Helper class for Paragraph Metrics.
-/// \todo FIXME: this class deserves its own .[Ch] files.
-/// Then, the storage of such object should be done in \c BufferView
-/// (most probably in the \c CoordCache class along \c Point objects).
-class ParagraphMetrics {
-public:
- ///
- Row & getRow(pos_type pos, bool boundary);
- ///
- Row const & getRow(pos_type pos, bool boundary) const;
- ///
- size_t pos2row(pos_type pos) const;
- /// LyXText::redoParagraph updates this
- Dimension & dim() { return dim_; }
- /// total height of paragraph
- unsigned int height() const { return dim_.height(); }
- /// total width of paragraph, may differ from workwidth
- unsigned int width() const { return dim_.width(); }
- /// ascend of paragraph above baseline
- unsigned int ascent() const { return dim_.ascent(); }
- /// descend of paragraph below baseline
- unsigned int descent() const { return dim_.descent(); }
- /// LyXText updates the rows using this access point
- RowList & rows() { return rows_; }
- /// The painter and others use this
- RowList const & rows() const { return rows_; }
- ///
- RowSignature & rowSignature() const { return rowSignature_; }
-
- /// dump some information to lyxerr
- void dump() const;
-
-private:
- ///
- mutable RowList rows_;
- ///
- mutable RowSignature rowSignature_;
- /// cached dimensions of paragraph
- Dimension dim_;
-};
-
-
/// A Paragraph holds all text, attributes and insets in a text paragraph
/// \todo FIXME: any reference to ParagraphMetrics (including inheritance)
/// should go in order to complete the Model/View separation of this class.
-class Paragraph: public ParagraphMetrics {
+class Paragraph {
public:
///
enum {
@@ -406,6 +364,10 @@
///
bool hfillExpansion(Row const & row, pos_type pos) const;
+ /// Check if we are in a Biblio environment.
+ /// \retval true if the cursor needs to be moved right.
+ bool checkBiblio(bool track_changes);
+
public:
///
InsetList insetlist;
@@ -430,6 +392,57 @@
Pimpl * pimpl_;
};
+/// Helper class for Paragraph Metrics.
+/// \todo FIXME: this class deserves its own .[Ch] files.
+/// Then, the storage of such object should be done in \c BufferView
+/// (most probably in the \c CoordCache class along \c Point objects).
+class ParagraphMetrics {
+public:
+ ///
+ ParagraphMetrics(): par_(0) {};
+ ///
+ ParagraphMetrics(Paragraph const & par);
+ ///
+ Row & getRow(pos_type pos, bool boundary);
+ ///
+ Row const & getRow(pos_type pos, bool boundary) const;
+ ///
+ size_t pos2row(pos_type pos) const;
+
+ /// BufferView::redoParagraph updates this
+ Dimension const & dim() const { return dim_; }
+ Dimension & dim() { return dim_; }
+ /// total height of paragraph
+ unsigned int height() const { return dim_.height(); }
+ /// total width of paragraph, may differ from workwidth
+ unsigned int width() const { return dim_.width(); }
+ /// ascend of paragraph above baseline
+ unsigned int ascent() const { return dim_.ascent(); }
+ /// descend of paragraph below baseline
+ unsigned int descent() const { return dim_.descent(); }
+ /// LyXText updates the rows using this access point
+ RowList & rows() { return rows_; }
+ /// The painter and others use this
+ RowList const & rows() const { return rows_; }
+ ///
+ RowSignature & rowSignature() const { return rowSignature_; }
+ ///
+ int rightMargin(Buffer const & buffer) const;
+
+ /// dump some information to lyxerr
+ void dump() const;
+
+private:
+ ///
+ mutable RowList rows_;
+ ///
+ mutable RowSignature rowSignature_;
+ /// cached dimensions of paragraph
+ Dimension dim_;
+ ///
+ Paragraph const * par_;
+};
+
} // namespace lyx
#endif // PARAGRAPH_H
Index: paragraph_funcs.C
===================================================================
--- paragraph_funcs.C (revision 16395)
+++ paragraph_funcs.C (working copy)
@@ -68,9 +68,6 @@
Paragraph & par = pars[par_offset];
- // we will invalidate the row cache
- par.rows().clear();
-
// without doing that we get a crash when typing <Return> at the
// end of a paragraph
tmp->layout(bparams.getLyXTextClass().defaultLayout());
Index: rowpainter.C
===================================================================
--- rowpainter.C (revision 16395)
+++ rowpainter.C (working copy)
@@ -106,6 +106,7 @@
/// Row's paragraph
pit_type const pit_;
Paragraph const & par_;
+ ParagraphMetrics const & pm_;
/// is row erased? (change tracking)
bool erased_;
@@ -125,10 +126,13 @@
LyXText const & text, pit_type pit, Row const & row, int x, int y)
: bv_(*pi.base.bv), pain_(pi.pain), text_(text),
pars_(text.paragraphs()),
row_(row), pit_(pit), par_(text.paragraphs()[pit]),
+ pm_(pi.base.bv->parMetrics(&text, pit)),
erased_(pi.erased_),
xo_(x), yo_(y), width_(text_.width())
{
- RowMetrics m = text_.computeRowMetrics(*bv_.buffer(), pit, row_);
+ Buffer const & buffer = *bv_.buffer();
+ int const right_margin = text_.isMainText(buffer)?
pm_.rightMargin(buffer) : 0;
+ RowMetrics m = text_.computeRowMetrics(*bv_.buffer(), right_margin,
pit_, row_);
x_ = m.x + xo_;
//lyxerr << "RowPainter: x: " << x_ << " xo: " << xo_ << " yo: " << yo_
<< endl;
@@ -193,7 +197,8 @@
#ifdef DEBUG_METRICS
Dimension dim;
BOOST_ASSERT(text_.maxwidth_ > 0);
- int const w = text_.maxwidth_ - leftMargin() -
text_.rightMargin(*bv_.buffer(), par_);
+ int right_margin = text_.isMainText()? pm_.rightMargin(bv_->buffer()) :
0;
+ int const w = text_.maxwidth_ - leftMargin() - right_margin;
MetricsInfo mi(&bv_, font, w);
inset->metrics(mi, dim);
if (inset->width() > dim.wid)
@@ -620,7 +625,7 @@
if (layout->labeltype ==
LABEL_CENTERED_TOP_ENVIRONMENT) {
if (is_rtl)
x = leftMargin();
- x += (width_ - text_.rightMargin(buffer, par_)
- leftMargin()) / 2;
+ x += (width_ - text_.rightMargin(buffer, pm_) -
leftMargin()) / 2;
x -= fm.width(str) / 2;
} else if (is_rtl) {
x = width_ - leftMargin() - fm.width(str);
@@ -872,11 +877,12 @@
pi.base.bv->coordCache().parPos()[&text][pit] = Point(x, y);
Paragraph const & par = text.paragraphs()[pit];
- if (par.rows().empty())
+ ParagraphMetrics const & pm = pi.base.bv->parMetrics(&text, pit);
+ if (pm.rows().empty())
return;
- RowList::const_iterator const rb = par.rows().begin();
- RowList::const_iterator const re = par.rows().end();
+ RowList::const_iterator const rb = pm.rows().begin();
+ RowList::const_iterator const re = pm.rows().end();
y -= rb->ascent();
size_type rowno = 0;
@@ -888,7 +894,7 @@
// Row signature; has row changed since last paint?
size_type const row_sig = calculateRowSignature(*rit, par, x,
y);
- bool row_has_changed = par.rowSignature()[rowno] != row_sig;
+ bool row_has_changed = pm.rowSignature()[rowno] != row_sig;
bool cursor_on_row = CursorOnRow(pi, pit, rit, text);
bool in_inset_alone_on_row = innerCursorOnRow(pi, pit, rit,
@@ -917,7 +923,7 @@
// then paint the row
if (repaintAll || row_has_changed || cursor_on_row) {
// Add to row signature cache
- par.rowSignature()[rowno] = row_sig;
+ pm.rowSignature()[rowno] = row_sig;
bool const inside = (y + rit->descent() >= 0
&& y - rit->ascent() < ww);
@@ -998,10 +1004,10 @@
// draw contents
for (pit_type pit = vi.p1; pit <= vi.p2; ++pit) {
refreshInside = repaintAll;
- Paragraph const & par = text.getPar(pit);
- yy += par.ascent();
+ ParagraphMetrics const & pm = bv.parMetrics(&text, pit);
+ yy += pm.ascent();
paintPar(pi, text, pit, 0, yy, repaintAll);
- yy += par.descent();
+ yy += pm.descent();
}
// and grey out above (should not happen later)
@@ -1020,13 +1026,15 @@
{
// lyxerr << " paintTextInset: y: " << y << endl;
- y -= text.getPar(0).ascent();
+ y -= pi.base.bv->parMetrics(&text, 0).ascent();
// This flag cannot be set from within same inset:
bool repaintAll = refreshInside;
for (int pit = 0; pit < int(text.paragraphs().size()); ++pit) {
- y += text.getPar(pit).ascent();
+ ParagraphMetrics const & pmi
+ = pi.base.bv->parMetrics(&text, pit);
+ y += pmi.ascent();
paintPar(pi, text, pit, x, y, repaintAll);
- y += text.getPar(pit).descent();
+ y += pmi.descent();
}
}
Index: text.C
===================================================================
--- text.C (revision 16395)
+++ text.C (working copy)
@@ -648,27 +648,15 @@
}
-int LyXText::rightMargin(Buffer const & buffer, Paragraph const & par) const
+int LyXText::rightMargin(Buffer const & buffer, ParagraphMetrics const & pm)
const
{
// FIXME: the correct way is to only call rightMargin() only
// within the main LyXText. The following test is thus bogus.
- LyXText const & text = buffer.text();
+
// We do not want rightmargins on inner texts.
- if (&text != this)
- return 0;
+ int right_margin = isMainText(buffer)? pm.rightMargin(buffer) : 0;
- BufferParams const & params = buffer.params();
- LyXTextClass const & tclass = params.getLyXTextClass();
- docstring trmarg = from_utf8(tclass.rightmargin());
- docstring lrmarg = from_utf8(par.layout()->rightmargin);
- FontMetrics const & fm = theFontMetrics(params.getFont());
- int const r_margin =
- lyx::rightMargin()
- + fm.signedWidth(trmarg)
- + fm.signedWidth(lrmarg)
- * 4 / (par.getDepth() + 4);
-
- return r_margin;
+ return right_margin;
}
@@ -731,6 +719,7 @@
// or the end of the par, then choose the possible break
// nearest that.
+ int label_end = labelEnd(buffer, pit);
int const left = leftMargin(buffer, pit, pos);
int x = left;
@@ -752,7 +741,7 @@
if (par.isLineSeparator(i - 1))
add -= singleWidth(buffer, par, i - 1);
- add = std::max(add, labelEnd(buffer, pit) - x);
+ add = std::max(add, label_end - x);
thiswidth += add;
}
@@ -815,7 +804,8 @@
}
-void LyXText::setRowWidth(Buffer const & buffer, pit_type const pit, Row &
row) const
+void LyXText::setRowWidth(Buffer const & buffer, int right_margin,
+ pit_type const pit, Row & row) const
{
// get the pure distance
pos_type const end = row.endpos();
@@ -823,6 +813,7 @@
Paragraph const & par = pars_[pit];
docstring const labelsep = from_utf8(par.layout()->labelsep);
int w = leftMargin(buffer, pit, row.pos());
+ int label_end = labelEnd(buffer, pit);
pos_type const body_pos = par.beginOfBody();
pos_type i = row.pos();
@@ -836,7 +827,7 @@
w += fm.width(labelsep);
if (par.isLineSeparator(i - 1))
w -= singleWidth(buffer, par, i - 1);
- w = max(w, labelEnd(buffer, pit));
+ w = max(w, label_end);
}
char_type const c = par.getChar(i);
w += singleWidth(par, i, c, *fi);
@@ -847,10 +838,10 @@
w += fm.width(labelsep);
if (end > 0 && par.isLineSeparator(end - 1))
w -= singleWidth(buffer, par, end - 1);
- w = max(w, labelEnd(buffer, pit));
+ w = max(w, label_end);
}
- row.width(w + rightMargin(buffer, par));
+ row.width(w + right_margin);
}
@@ -1140,22 +1131,15 @@
updateLabels(cur.buffer(), current_it, last_it);
- // FIXME: Breaking a paragraph has nothing to do with setting a cursor.
- // Because of the mix between the model (the paragraph contents) and the
- // view (the paragraph breaking in rows, we have to do this here before
- // the setCursor() call below.
- bool changed_height = redoParagraph(cur.bv(), cpit);
- changed_height |= redoParagraph(cur.bv(), cpit + 1);
- if (changed_height)
- // A singlePar update is not enough in this case.
- cur.updateFlags(Update::Force);
+ // A singlePar update is not enough in this case.
+ cur.updateFlags(Update::Force);
// This check is necessary. Otherwise the new empty paragraph will
// be deleted automatically. And it is more friendly for the user!
if (cur.pos() != 0 || isempty)
- setCursor(cur, cur.pit() + 1, 0);
+ setCursor(cur.top(), cur.pit() + 1, 0);
else
- setCursor(cur, cur.pit(), 0);
+ setCursor(cur.top(), cur.pit(), 0);
}
@@ -1244,13 +1228,8 @@
par.insertChar(cur.pos(), c, current_font,
cur.buffer().params().trackChanges);
- // FIXME: Inserting a character has nothing to do with setting a cursor.
- // Because of the mix between the model (the paragraph contents) and the
- // view (the paragraph breaking in rows, we have to do this here.
- if (redoParagraph(cur.bv(), cur.pit()))
- // A singlePar update is not enough in this case.
- cur.updateFlags(Update::Force);
- setCursor(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
+// cur.updateFlags(Update::Force);
+ setCursor(cur.top(), cur.pit(), cur.pos() + 1);
charInserted();
}
@@ -1270,7 +1249,7 @@
RowMetrics LyXText::computeRowMetrics(Buffer const & buffer,
- pit_type const pit, Row const & row) const
+ int right_margin, pit_type const pit, Row const & row) const
{
RowMetrics result;
Paragraph const & par = pars_[pit];
@@ -1279,7 +1258,7 @@
bool const is_rtl = isRTL(buffer, par);
if (is_rtl)
- result.x = rightMargin(buffer, par);
+ result.x = right_margin;
else
result.x = leftMargin(buffer, pit, row.pos());
@@ -1657,17 +1636,10 @@
}
}
- // FIXME: Inserting characters has nothing to do with setting a cursor.
- // Because of the mix between the model (the paragraph contents)
- // and the view (the paragraph breaking in rows, we have to do this
- // here before the setCursorIntern() call.
if (needsUpdate) {
- if (redoParagraph(cur.bv(), cur.pit()))
- // A singlePar update is not enough in this case.
- cur.updateFlags(Update::Force);
// Make sure the cursor is correct. Is this really needed?
// No, not really... at least not here!
- cur.text()->setCursorIntern(cur, cur.pit(), cur.pos());
+ cur.text()->setCursor(cur.top(), cur.pit(), cur.pos());
}
return needsUpdate;
@@ -1760,14 +1732,9 @@
if (cur.pos() == cur.lastpos())
setCurrentFont(cur);
- // FIXME: Backspacing has nothing to do with setting a cursor.
- // Because of the mix between the model (the paragraph contents)
- // and the view (the paragraph breaking in rows, we have to do this
- // here before the setCursor() call.
- if (redoParagraph(cur.bv(), cur.pit()))
- // A singlePar update is not enough in this case.
- cur.updateFlags(Update::Force);
- setCursor(cur, cur.pit(), cur.pos(), false, cur.boundary());
+ // A singlePar update is not enough in this case.
+// cur.updateFlags(Update::Force);
+ setCursor(cur.top(), cur.pit(), cur.pos());
return needsUpdate;
}
@@ -1821,104 +1788,6 @@
}
-Row const & LyXText::firstRow() const
-{
- return *paragraphs().front().rows().begin();
-}
-
-
-bool LyXText::redoParagraph(BufferView & bv, pit_type const pit)
-{
- // remove rows of paragraph, keep track of height changes
- Paragraph & par = pars_[pit];
- Buffer const & buffer = *bv.buffer();
-
- bool changed = false;
-
- // Add bibitem insets if necessary
- if (par.layout()->labeltype == LABEL_BIBLIO) {
- bool hasbibitem(false);
- if (!par.insetlist.empty()
- // Insist on it being in pos 0
- && par.getChar(0) == Paragraph::META_INSET) {
- InsetBase * inset = par.insetlist.begin()->inset;
- if (inset->lyxCode() == InsetBase::BIBITEM_CODE)
- hasbibitem = true;
- }
- if (!hasbibitem) {
- InsetBibitem * inset(new
- InsetBibitem(InsetCommandParams("bibitem")));
- par.insertInset(0, static_cast<InsetBase *>(inset),
- Change(buffer.params().trackChanges ?
- Change::INSERTED :
Change::UNCHANGED));
- bv.cursor().posRight();
- }
- }
-
- // Optimisation: this is used in the next two loops
- // so better to calculate that once here.
- int right_margin = rightMargin(buffer, par);
-
- // redo insets
- // FIXME: We should always use getFont(), see documentation of
- // noFontChange() in insetbase.h.
- LyXFont const bufferfont = buffer.params().getFont();
- InsetList::const_iterator ii = par.insetlist.begin();
- InsetList::const_iterator iend = par.insetlist.end();
- for (; ii != iend; ++ii) {
- Dimension dim;
- int const w = maxwidth_ - leftMargin(buffer, pit, ii->pos)
- - right_margin;
- LyXFont const & font = ii->inset->noFontChange() ?
- bufferfont :
- getFont(buffer, par, ii->pos);
- MetricsInfo mi(&bv, font, w);
- changed |= ii->inset->metrics(mi, dim);
- }
-
- // rebreak the paragraph
- par.rows().clear();
- Dimension dim;
-
- par.setBeginOfBody();
- pos_type z = 0;
- do {
- Row row(z);
- rowBreakPoint(buffer, right_margin, pit, row);
- setRowWidth(buffer, pit, row);
- setHeightOfRow(bv, pit, row);
- par.rows().push_back(row);
- dim.wid = std::max(dim.wid, row.width());
- dim.des += row.height();
- z = row.endpos();
- } while (z < par.size());
-
- // Make sure that if a par ends in newline, there is one more row
- // under it
- // FIXME this is a dirty trick. Now the _same_ position in the
- // paragraph occurs in _two_ different rows, and has two different
- // display positions, leading to weird behaviour when moving up/down.
- if (z > 0 && par.isNewline(z - 1)) {
- Row row(z - 1);
- row.endpos(z - 1);
- setRowWidth(buffer, pit, row);
- setHeightOfRow(bv, pit, row);
- par.rows().push_back(row);
- dim.des += row.height();
- }
-
- dim.asc += par.rows()[0].ascent();
- dim.des -= par.rows()[0].ascent();
-
- changed |= dim.height() != par.dim().height();
-
- par.dim() = dim;
- //lyxerr << "redoParagraph: " << par.rows().size() << " rows\n";
-
- return changed;
-}
-
-
bool LyXText::metrics(MetricsInfo & mi, Dimension & dim)
{
//BOOST_ASSERT(mi.base.textwidth);
@@ -1934,15 +1803,16 @@
unsigned int h = 0;
unsigned int w = 0;
for (pit_type pit = 0, n = paragraphs().size(); pit != n; ++pit) {
- changed |= redoParagraph(*mi.base.bv, pit);
- Paragraph & par = paragraphs()[pit];
- h += par.height();
- if (w < par.width())
- w = par.width();
+ changed |= mi.base.bv->redoParagraph(this, pit);
+ ParagraphMetrics const & pm = mi.base.bv->parMetrics(this, pit);
+ h += pm.height();
+ if (w < pm.width())
+ w = pm.width();
}
+ ParagraphMetrics const & pm0 = mi.base.bv->parMetrics(this, 0);
dim.wid = w;
- dim.asc = pars_[0].ascent();
+ dim.asc = pm0.ascent();
dim.des = h - dim.asc;
changed |= dim_ != dim;
@@ -1987,6 +1857,8 @@
Paragraph const & par1 = pars_[beg.pit()];
Paragraph const & par2 = pars_[end.pit()];
+ ParagraphMetrics const & pm1 = bv.parMetrics(this, beg.pit());
+ ParagraphMetrics const & pm2 = bv.parMetrics(this, end.pit());
bool const above = (bv_funcs::status(&bv, beg)
== bv_funcs::CUR_ABOVE);
@@ -1999,10 +1871,10 @@
x1 = 0;
x2 = dim_.wid;
} else {
- Row const & row1 = par1.getRow(beg.pos(), beg.boundary());
+ Row const & row1 = pm1.getRow(beg.pos(), beg.boundary());
y1 = bv_funcs::getPos(bv, beg, beg.boundary()).y_ -
row1.ascent();
y2 = y1 + row1.height();
- int const startx = cursorX(buffer, beg.top(), beg.boundary());
+ int const startx = cursorX(bv, beg.top(), beg.boundary());
if (!isRTL(buffer, par1)) {
x1 = startx;
x2 = 0 + dim_.wid;
@@ -2020,10 +1892,10 @@
X1 = 0;
X2 = dim_.wid;
} else {
- Row const & row2 = par2.getRow(end.pos(), end.boundary());
+ Row const & row2 = pm2.getRow(end.pos(), end.boundary());
Y1 = bv_funcs::getPos(bv, end, end.boundary()).y_ -
row2.ascent();
Y2 = Y1 + row2.height();
- int const endx = cursorX(buffer, end.top(), end.boundary());
+ int const endx = cursorX(bv, end.top(), end.boundary());
if (!isRTL(buffer, par2)) {
X1 = 0;
X2 = endx;
@@ -2034,8 +1906,8 @@
}
}
- if (!above && !below && &par1.getRow(beg.pos(), beg.boundary())
- == &par2.getRow(end.pos(), end.boundary()))
+ if (!above && !below && &pm1.getRow(beg.pos(), beg.boundary())
+ == &pm2.getRow(end.pos(), end.boundary()))
{
// paint only one rectangle
int const b( !isRTL(*bv.buffer(), par1) ? x + x1 : x + X1 );
@@ -2188,12 +2060,13 @@
}
-int LyXText::cursorX(Buffer const & buffer, CursorSlice const & sl,
+int LyXText::cursorX(BufferView const & bv, CursorSlice const & sl,
bool boundary) const
{
pit_type const pit = sl.pit();
Paragraph const & par = pars_[pit];
- if (par.rows().empty())
+ ParagraphMetrics const & pm = bv.parMetrics(sl.text(), pit);
+ if (pm.rows().empty())
return 0;
pos_type ppos = sl.pos();
@@ -2202,11 +2075,13 @@
if (boundary_correction)
--ppos;
- Row const & row = par.getRow(sl.pos(), boundary);
+ Row const & row = pm.getRow(sl.pos(), boundary);
pos_type cursor_vpos = 0;
- RowMetrics const m = computeRowMetrics(buffer, pit, row);
+ Buffer const & buffer = *bv.buffer();
+ int const right_margin = isMainText(buffer)? pm.rightMargin(buffer) : 0;
+ RowMetrics const m = computeRowMetrics(buffer, right_margin, pit, row);
double x = m.x;
pos_type const row_pos = row.pos();
@@ -2279,24 +2154,25 @@
}
-int LyXText::cursorY(CursorSlice const & sl, bool boundary) const
+int LyXText::cursorY(BufferView const & bv, CursorSlice const & sl, bool
boundary) const
{
//lyxerr << "LyXText::cursorY: boundary: " << boundary << std::endl;
- Paragraph const & par = getPar(sl.pit());
- if (par.rows().empty())
+ ParagraphMetrics const & pm = bv.parMetrics(this, sl.pit());
+ if (pm.rows().empty())
return 0;
int h = 0;
- h -= pars_[0].rows()[0].ascent();
- for (pit_type pit = 0; pit < sl.pit(); ++pit)
- h += pars_[pit].height();
+ h -= bv.parMetrics(this, 0).rows()[0].ascent();
+ for (pit_type pit = 0; pit < sl.pit(); ++pit) {
+ h += bv.parMetrics(this, pit).height();
+ }
int pos = sl.pos();
if (pos && boundary)
--pos;
- size_t const rend = par.pos2row(pos);
+ size_t const rend = pm.pos2row(pos);
for (size_t rit = 0; rit != rend; ++rit)
- h += par.rows()[rit].height();
- h += par.rows()[rend].ascent();
+ h += pm.rows()[rit].height();
+ h += pm.rows()[rend].ascent();
return h;
}
@@ -2447,11 +2323,14 @@
pos_type LyXText::x2pos(BufferView const & bv, pit_type pit, int row,
int x) const
{
- BOOST_ASSERT(!pars_[pit].rows().empty());
- BOOST_ASSERT(row < int(pars_[pit].rows().size()));
+ ParagraphMetrics const & pm = bv.parMetrics(this, pit);
+ BOOST_ASSERT(!pm.rows().empty());
+ BOOST_ASSERT(row < int(pm.rows().size()));
bool bound = false;
- Row const & r = pars_[pit].rows()[row];
- return r.pos() + getColumnNearX(bv, pit, r, x, bound);
+ Row const & r = pm.rows()[row];
+ Buffer const & buffer = *bv.buffer();
+ int right_margin = isMainText(buffer)? pm.rightMargin(buffer) : 0;
+ return r.pos() + getColumnNearX(bv, right_margin, pit, r, x, bound);
}
@@ -2470,7 +2349,10 @@
{
BOOST_ASSERT(this == cur.text());
pit_type pit = getPitNearY(cur.bv(), y);
- int yy = cur.bv().coordCache().get(this, pit).y_ - pars_[pit].ascent();
+
+ ParagraphMetrics const & pm = cur.bv().parMetrics(this, pit);
+
+ int yy = cur.bv().coordCache().get(this, pit).y_ - pm.ascent();
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
<< ": x: " << x
@@ -2478,17 +2360,16 @@
<< " pit: " << pit
<< " yy: " << yy << endl;
- Paragraph const & par = pars_[pit];
int r = 0;
- BOOST_ASSERT(par.rows().size());
- for (; r < int(par.rows().size()) - 1; ++r) {
- Row const & row = par.rows()[r];
+ BOOST_ASSERT(pm.rows().size());
+ for (; r < int(pm.rows().size()) - 1; ++r) {
+ Row const & row = pm.rows()[r];
if (int(yy + row.height()) > y)
break;
yy += row.height();
}
- Row const & row = par.rows()[r];
+ Row const & row = pm.rows()[r];
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
@@ -2498,8 +2379,10 @@
bool bound = false;
int xx = x;
- pos_type const pos = row.pos() + getColumnNearX(cur.bv(), pit, row,
- xx, bound);
+ Buffer const & buffer = cur.buffer();
+ int right_margin = isMainText(buffer)? pm.rightMargin(buffer) : 0;
+ pos_type const pos = row.pos() + getColumnNearX(cur.bv(), right_margin,
+ pit, row, xx, bound);
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
Index: text2.C
===================================================================
--- text2.C (revision 16395)
+++ text2.C (working copy)
@@ -87,10 +87,6 @@
dim_.asc = 10;
dim_.des = 10;
- pit_type const end = paragraphs().size();
- for (pit_type pit = 0; pit != end; ++pit)
- pars_[pit].rows().clear();
-
updateLabels(*bv->buffer());
}
@@ -502,7 +498,8 @@
bool LyXText::cursorHome(LCursor & cur)
{
BOOST_ASSERT(this == cur.text());
- Row const & row = cur.paragraph().getRow(cur.pos(),cur.boundary());
+ ParagraphMetrics const & pm = cur.bv().parMetrics(this, cur.pit());
+ Row const & row = pm.getRow(cur.pos(),cur.boundary());
return setCursor(cur, cur.pit(), row.pos());
}
@@ -719,7 +716,6 @@
BOOST_ASSERT(this == cur.text());
cur.boundary(boundary);
setCursor(cur.top(), par, pos);
- cur.setTargetX();
if (setfont)
setCurrentFont(cur);
}
@@ -767,13 +763,13 @@
// x is an absolute screen coord
// returns the column near the specified x-coordinate of the row
// x is set to the real beginning of this column
-pos_type LyXText::getColumnNearX(BufferView const & bv, pit_type const pit,
- Row const & row, int & x, bool & boundary)
const
+pos_type LyXText::getColumnNearX(BufferView const & bv, int right_margin,
+ pit_type const pit, Row const & row, int & x, bool & boundary)
const
{
Buffer const & buffer = *bv.buffer();
int const xo = bv.coordCache().get(this, pit).x_;
x -= xo;
- RowMetrics const r = computeRowMetrics(buffer, pit, row);
+ RowMetrics const r = computeRowMetrics(buffer, right_margin, pit, row);
Paragraph const & par = pars_[pit];
pos_type vc = row.pos();
@@ -921,35 +917,39 @@
CoordCache::InnerParPosCache::const_iterator et = cc.end();
CoordCache::InnerParPosCache::const_iterator last = et; last--;
+ ParagraphMetrics const & pm = bv.parMetrics(this, it->first);
+
// If we are off-screen (before the visible part)
if (y < 0
// and even before the first paragraph in the cache.
- && y < it->second.y_ - int(pars_[it->first].ascent())) {
+ && y < it->second.y_ - int(pm.ascent())) {
// and we are not at the first paragraph in the inset.
if (it->first == 0)
return 0;
// then this is the paragraph we are looking for.
pit = it->first - 1;
// rebreak it and update the CoordCache.
- redoParagraph(bv, pit);
+ bv.redoParagraph(this, pit);
bv.coordCache().parPos()[this][pit] =
- Point(0, it->second.y_ - pars_[it->first].descent());
+ Point(0, it->second.y_ - pm.descent());
return pit;
}
+ ParagraphMetrics const & pm_last = bv.parMetrics(this, last->first);
+
// If we are off-screen (after the visible part)
if (y > bv.workHeight()
// and even after the first paragraph in the cache.
- && y >= last->second.y_ + int(pars_[last->first].descent())) {
+ && y >= last->second.y_ + int(pm_last.descent())) {
pit = last->first + 1;
// and we are not at the last paragraph in the inset.
if (pit == int(pars_.size()))
return last->first;
// then this is the paragraph we are looking for.
// rebreak it and update the CoordCache.
- redoParagraph(bv, pit);
+ bv.redoParagraph(this, pit);
bv.coordCache().parPos()[this][pit] =
- Point(0, last->second.y_ + pars_[last->first].ascent());
+ Point(0, last->second.y_ + pm_last.ascent());
return pit;
}
@@ -960,7 +960,9 @@
<< " y: " << it->second.y_
<< endl;
- if (it->first >= pit && int(it->second.y_) -
int(pars_[it->first].ascent()) <= y) {
+ ParagraphMetrics const & pm = bv.parMetrics(this, it->first);
+
+ if (it->first >= pit && int(it->second.y_) - int(pm.ascent())
<= y) {
pit = it->first;
yy = it->second.y_;
}
@@ -978,10 +980,12 @@
Row const & LyXText::getRowNearY(BufferView const & bv, int y, pit_type pit)
const
{
Paragraph const & par = pars_[pit];
- int yy = bv.coordCache().get(this, pit).y_ - par.ascent();
- BOOST_ASSERT(!par.rows().empty());
- RowList::const_iterator rit = par.rows().begin();
- RowList::const_iterator const rlast = boost::prior(par.rows().end());
+ ParagraphMetrics const & pm = bv.parMetrics(this, pit);
+
+ int yy = bv.coordCache().get(this, pit).y_ - pm.ascent();
+ BOOST_ASSERT(!pm.rows().empty());
+ RowList::const_iterator rit = pm.rows().begin();
+ RowList::const_iterator const rlast = boost::prior(pm.rows().end());
for (; rit != rlast; yy += rit->height(), ++rit)
if (yy + rit->height() > y)
break;
@@ -999,18 +1003,16 @@
}
pit_type pit = getPitNearY(cur.bv(), y);
BOOST_ASSERT(pit != -1);
- // When another window is opened with the same document, rows()
- // will be cleared so pars_[pit].rows() might be empty when switching
- // between windwos. A better solution is that each buffer view
- // has its own rows() for the same buffer.
- if (pars_[pit].rows().empty())
- redoParagraph(cur.bv(), pit);
+
Row const & row = getRowNearY(cur.bv(), y, pit);
bool bound = false;
+ ParagraphMetrics const & pm = cur.bv().parMetrics(this, pit);
+ Buffer const & buffer = cur.buffer();
+ int right_margin = isMainText(buffer)? pm.rightMargin(buffer) : 0;
int xx = x; // is modified by getColumnNearX
pos_type const pos = row.pos()
- + getColumnNearX(cur.bv(), pit, row, xx, bound);
+ + getColumnNearX(cur.bv(), right_margin, pit, row, xx, bound);
cur.pit() = pit;
cur.pos() = pos;
cur.boundary(bound);
@@ -1131,13 +1133,15 @@
cur.updateFlags(Update::FitCursor);
Paragraph const & par = cur.paragraph();
+ ParagraphMetrics const & pm = cur.bv().parMetrics(this, cur.pit());
+
int row;
int const x = cur.targetX();
if (cur.pos() && cur.boundary())
- row = par.pos2row(cur.pos()-1);
+ row = pm.pos2row(cur.pos()-1);
else
- row = par.pos2row(cur.pos());
+ row = pm.pos2row(cur.pos());
if (!cur.selection()) {
int const y = bv_funcs::getPos(cur.bv(), cur,
cur.boundary()).y_;
@@ -1145,7 +1149,7 @@
// Go to middle of previous row. 16 found to work OK;
// 12 = top/bottom margin of display math
int const margin = 3 * InsetMathHull::displayMargin() / 2;
- editXY(cur, x, y - par.rows()[row].ascent() - margin);
+ editXY(cur, x, y - pm.rows()[row].ascent() - margin);
cur.clearSelection();
// This happens when you move out of an inset.
@@ -1167,8 +1171,9 @@
} else if (cur.pit() > 0) {
--cur.pit();
//cannot use 'par' now
+ ParagraphMetrics const & pmcur = cur.bv().parMetrics(this,
cur.pit());
updateNeeded |= setCursor(cur, cur.pit(),
- x2pos(cur.bv(), cur.pit(),
cur.paragraph().rows().size() - 1, x));
+ x2pos(cur.bv(), cur.pit(), pmcur.rows().size() - 1, x));
}
cur.x_target() = x;
@@ -1183,20 +1188,22 @@
cur.updateFlags(Update::FitCursor);
Paragraph const & par = cur.paragraph();
+ ParagraphMetrics const & pm = cur.bv().parMetrics(this, cur.pit());
+
int row;
int const x = cur.targetX();
if (cur.pos() && cur.boundary())
- row = par.pos2row(cur.pos()-1);
+ row = pm.pos2row(cur.pos()-1);
else
- row = par.pos2row(cur.pos());
+ row = pm.pos2row(cur.pos());
if (!cur.selection()) {
int const y = bv_funcs::getPos(cur.bv(), cur,
cur.boundary()).y_;
LCursor old = cur;
// To middle of next row
int const margin = 3 * InsetMathHull::displayMargin() / 2;
- editXY(cur, x, y + par.rows()[row].descent() + margin);
+ editXY(cur, x, y + pm.rows()[row].descent() + margin);
cur.clearSelection();
// This happens when you move out of an inset.
@@ -1218,7 +1225,7 @@
bool updateNeeded = false;
- if (row + 1 < int(par.rows().size())) {
+ if (row + 1 < int(pm.rows().size())) {
updateNeeded |= setCursor(cur, cur.pit(),
x2pos(cur.bv(), cur.pit(), row + 1, x));
} else if (cur.pit() + 1 < int(paragraphs().size())) {
@@ -1322,7 +1329,7 @@
&& !oldpar.isDeleted(old.pos() - 1)) {
oldpar.eraseChar(old.pos() - 1, false); // do not track
changes in DEPM
// rebreak it and update the CoordCache.
- redoParagraph(cur.bv(), old.pit());
+ cur.bv().redoParagraph(this, old.pit());
#ifdef WITH_WARNINGS
#warning This will not work anymore when we have multiple views of the same
buffer
// In this case, we will have to correct also the cursors held by
Index: text3.C
===================================================================
--- text3.C (revision 16395)
+++ text3.C (working copy)
@@ -333,7 +333,9 @@
bool needsUpdate = !(lyxaction.funcHasFlag(cmd.action,
LyXAction::NoUpdate) || singleParUpdate);
// Remember the old paragraph metric (_outer_ paragraph!)
- Dimension olddim = cur.bottom().paragraph().dim();
+ ParagraphMetrics const & pm = cur.bv().parMetrics(
+ cur.bottom().text(), cur.bottom().pit());
+ Dimension olddim = pm.dim();
switch (cmd.action) {
@@ -793,8 +795,8 @@
case LFUN_SERVER_GET_XY:
cur.message(from_utf8(
- convert<string>(cursorX(cur.buffer(), cur.top(),
cur.boundary()))
- + ' ' + convert<string>(cursorY(cur.top(),
cur.boundary()))));
+ convert<string>(cursorX(cur.bv(), cur.top(),
cur.boundary()))
+ + ' ' + convert<string>(cursorY(cur.bv(), cur.top(),
cur.boundary()))));
break;
case LFUN_SERVER_SET_XY: {
@@ -1514,9 +1516,11 @@
// FIXME: the following code should go in favor of fine grained
// update flag treatment.
- if (singleParUpdate)
+ if (singleParUpdate) {
// Inserting characters does not change par height
- if (cur.bottom().paragraph().dim().height()
+ ParagraphMetrics const & pms
+ = cur.bv().parMetrics(cur.bottom().text(),
cur.bottom().pit());
+ if (pms.dim().height()
== olddim.height()) {
// if so, update _only_ this paragraph
cur.updateFlags(Update::SinglePar |
@@ -1525,6 +1529,7 @@
return;
} else
needsUpdate = true;
+ }
if (!needsUpdate
&& &oldTopSlice.inset() == &cur.inset()