-/* This file is part of
- * ======================================================
+/**
+ * \file text.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
*
- * LyX, The Document Processor
+ * \author Asger Alstrup
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ * \author John Levon
+ * \author André Pönitz
+ * \author Dekel Tsur
+ * \author Jürgen Vigna
*
- * Copyright 1995 Matthias Ettrich
- * Copyright 1995-2001 The LyX Team.
- *
- * ====================================================== */
+ * Full author contact details are available in file CREDITS.
+ */
#include <config.h>
/// left margin
extern int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN;
+
+
int bibitemMaxWidth(BufferView *, LyXFont const &);
{
ParagraphList::iterator pit = ownerParagraphs().begin();
ParagraphList::iterator end = ownerParagraphs().end();
- for (int y = 0; pit != end; ++pit) {
+ for (height = 0; pit != end; ++pit) {
RowList::iterator rit = pit->rows.begin();
RowList::iterator rend = pit->rows.end();
for ( ; rit != rend ; rit = ++rit) {
- rit->y(y);
- y += rit->height();
+ rit->y(height);
+ height += rit->height();
}
}
}
-int LyXText::top_y() const
-{
- return anchor_y_;
-}
-
-
-void LyXText::top_y(int newy)
-{
- if (ownerParagraphs().begin()->rows.empty())
- return;
-
- anchor_y_ = newy;
- lyxerr[Debug::GUI] << "changing reference to offset: " << anchor_y_ << endl;
-}
-
-
int LyXText::workWidth() const
{
return inset_owner ? inset_owner->textWidth() : bv()->workWidth();
return 0;
char const c = pit->getChar(pos);
- return singleWidth(pit, pos, c);
+ LyXFont const & font = getFont(pit, pos);
+ return singleWidth(pit, pos, c, font);
}
int LyXText::singleWidth(ParagraphList::iterator pit,
- pos_type pos, char c) const
+ pos_type pos, char c, LyXFont const & font) const
{
- if (pos >= pit->size())
+ if (pos >= pit->size()) {
+ lyxerr << "in singleWidth(), pos: " << pos << endl;
+ Assert(false);
return 0;
+ }
- LyXFont const & font = getFont(pit, pos);
// The most common case is handled first (Asger)
if (IsPrintable(c)) {
if (c == Paragraph::META_INSET) {
InsetOld * tmpinset = pit->getInset(pos);
- if (tmpinset) {
- if (tmpinset->lyxCode() == InsetOld::HFILL_CODE) {
- // Because of the representation as vertical lines
- return 3;
- }
-#if 0
-#warning enabling this fixes the 'insets of width 0 on load' problem
- // this IS needed otherwise on initialitation we don't get the fill
- // of the row right (ONLY on initialization if we read a file!)
- // should be changed! (Jug 20011204)
- //tmpinset->update(bv());
- Dimension dim;
- MetricsInfo mi(bv(), font, workWidth());
- tmpinset->metrics(mi, dim);
- return dim.wid;
-#else
- return tmpinset->width();
-#endif
+ Assert(tmpinset);
+ if (tmpinset->lyxCode() == InsetOld::HFILL_CODE) {
+ // Because of the representation as vertical lines
+ return 3;
}
- return 0;
+ return tmpinset->width();
}
if (IsSeparatorChar(c))
void LyXText::computeBidiTables(ParagraphList::iterator pit,
- Buffer const * buf, RowList::iterator row) const
+ Buffer const & buf, RowList::iterator row) const
{
bidi_same_direction = true;
if (!lyxrc.rtl_support) {
pos_type stack[2];
bool const rtl_par =
- pit->isRightToLeftPar(buf->params);
+ pit->isRightToLeftPar(buf.params);
int level = 0;
bool rtl = false;
bool rtl0 = false;
!pit->isLineSeparator(lpos + 1) &&
!pit->isNewline(lpos + 1))
? lpos + 1 : lpos;
- LyXFont font = pit->getFontSettings(buf->params, pos);
+ LyXFont font = pit->getFontSettings(buf.params, pos);
if (pos != lpos && 0 < lpos && rtl0 && font.isRightToLeft() &&
font.number() == LyXFont::ON &&
- pit->getFontSettings(buf->params, lpos - 1).number()
+ pit->getFontSettings(buf.params, lpos - 1).number()
== LyXFont::ON) {
- font = pit->getFontSettings(buf->params, lpos);
+ font = pit->getFontSettings(buf.params, lpos);
is_space = false;
}
// This method requires a previous call to ComputeBidiTables()
-bool LyXText::isBoundary(Buffer const * buf, Paragraph const & par,
+bool LyXText::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos) const
{
if (!lyxrc.rtl_support || pos == 0)
bool const rtl = bidi_level(pos - 1) % 2;
bool const rtl2 = bidi_InRange(pos)
? bidi_level(pos) % 2
- : par.isRightToLeftPar(buf->params);
+ : par.isRightToLeftPar(buf.params);
return rtl != rtl2;
}
-bool LyXText::isBoundary(Buffer const * buf, Paragraph const & par,
+bool LyXText::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos, LyXFont const & font) const
{
if (!lyxrc.rtl_support)
bool const rtl = font.isVisibleRightToLeft();
bool const rtl2 = bidi_InRange(pos)
? bidi_level(pos) % 2
- : par.isRightToLeftPar(buf->params);
+ : par.isRightToLeftPar(buf.params);
return rtl != rtl2;
}
int LyXText::leftMargin(ParagraphList::iterator pit, Row const & row) const
-{
- InsetOld * ins;
-
- if (row.pos() < pit->size())
- if (pit->getChar(row.pos()) == Paragraph::META_INSET &&
- (ins = pit->getInset(row.pos())) &&
- (ins->needFullRow() || ins->display()))
- return LEFT_MARGIN;
-
+{
LyXTextClass const & tclass =
bv()->buffer()->params.getLyXTextClass();
LyXLayout_ptr const & layout = pit->layout();
int LyXText::rightMargin(ParagraphList::iterator pit,
- Buffer const & buf, Row const & row) const
+ Buffer const & buf, Row const &) const
{
- InsetOld * ins;
-
- if (row.pos() < pit->size())
- if ((pit->getChar(row.pos()) == Paragraph::META_INSET) &&
- (ins = pit->getInset(row.pos())) &&
- (ins->needFullRow() || ins->display()))
- return PAPER_MARGIN;
-
LyXTextClass const & tclass = buf.params.getLyXTextClass();
LyXLayout_ptr const & layout = pit->layout();
Row const & row) const
{
// maximum pixel width of a row.
- int width = workWidth() - rightMargin(pit, *bv()->buffer(), row);
+ int width = workWidth()
+ - rightMargin(pit, *bv()->buffer(), row);
// inset->textWidth() returns -1 via workWidth(),
// but why ?
// pixel width since last breakpoint
int chunkwidth = 0;
- bool fullrow = false;
pos_type i = pos;
}
char const c = pit->getChar(i);
+ if (i > endPosOfFontSpan) {
+ font = getFont(pit, i);
+ endPosOfFontSpan = pit->getEndPosOfFontSpan(i);
+ }
int thiswidth;
int left_margin = labelEnd(pit, row);
if (thiswidth + x < left_margin)
thiswidth = left_margin - x;
- thiswidth += singleWidth(pit, i, c);
+ thiswidth += singleWidth(pit, i, c, font);
} else {
- // Manual inlined optimised version of common case of "thiswidth = singleWidth(pit, i, c);"
- if (IsPrintable(c)) {
- if (pos > endPosOfFontSpan) {
- // We need to get the next font
- font = getFont(pit, i);
- endPosOfFontSpan = pit->getEndPosOfFontSpan(i);
- }
- if (! font.language()->RightToLeft()) {
- thiswidth = font_metrics::width(c, font);
- } else {
- // Fall-back to normal case
- thiswidth = singleWidth(pit, i, c);
- // And flush font cache
- endPosOfFontSpan = 0;
- }
- } else {
- // Fall-back to normal case
- thiswidth = singleWidth(pit, i, c);
- // And flush font cache
- endPosOfFontSpan = 0;
- }
+ thiswidth = singleWidth(pit, i, c, font);
}
x += thiswidth;
chunkwidth += thiswidth;
InsetOld * in = pit->isInset(i) ? pit->getInset(i) : 0;
- fullrow = in && (in->display() || in->needFullRow());
// break before a character that will fall off
// the right of the row
if (x >= width) {
- // if no break before or we are at an inset
- // that will take up a row, break here
- if (point == last || fullrow || chunkwidth >= (width - left)) {
+ // if no break before, break here
+ if (point == last || chunkwidth >= (width - left)) {
if (pos < i)
point = i - 1;
else
continue;
}
- if (!fullrow)
- continue;
-
- // full row insets start at a new row
- if (i == pos) {
- if (pos < last - 1) {
- point = i;
- if (pit->isLineSeparator(i + 1))
- ++point;
- } else {
- // to avoid extra rows
- point = last;
- }
- } else {
- point = i - 1;
- }
-
- return point;
+ continue;
}
if (point == last && x >= width) {
// manual labels cannot be broken in LaTeX. But we
// want to make our on-screen rendering of footnotes
// etc. still break
- if (!fullrow && body_pos && point < body_pos)
+ if (body_pos && point < body_pos)
point = body_pos - 1;
return point;
if (w < left_margin)
w = left_margin;
}
- { // Manual inlined an optimised version of the common case of "w += singleWidth(pit, i);"
- char const c = pit->getChar(i);
-
- if (IsPrintable(c)) {
- if (i > endPosOfFontSpan) {
- // We need to get the next font
- font = getFont(pit, i);
- endPosOfFontSpan = pit->getEndPosOfFontSpan(i);
- }
- if (!font.language()->RightToLeft()) {
- w += font_metrics::width(c, font);
- } else {
- // Fall-back to the normal case
- w += singleWidth(pit, i, c);
- // And flush font cache
- endPosOfFontSpan = 0;
- }
- } else {
- // Fall-back to the normal case
- w += singleWidth(pit, i, c);
- // And flush font cache
- endPosOfFontSpan = 0;
- }
+ char const c = pit->getChar(i);
+ if (IsPrintable(c) && i > endPosOfFontSpan) {
+ // We need to get the next font
+ font = getFont(pit, i);
+ endPosOfFontSpan = pit->getEndPosOfFontSpan(i);
}
+ w += singleWidth(pit, i, c, font);
++i;
}
}
maxwidth += font_metrics::width(c, font);
} else {
// Fall-back to normal case
- maxwidth += singleWidth(pit, pos, c);
+ maxwidth += singleWidth(pit, pos, c, font);
// And flush font cache
endPosOfFontSpan = 0;
}
if (par.isInset(pos)) {
InsetOld const * tmpinset = par.getInset(pos);
if (tmpinset) {
-#if 1 // this is needed for deep update on initialitation
-#warning inset->update FIXME
- //tmpinset->update(bv());
- LyXFont const tmpfont = getFont(pit, pos);
- Dimension dim;
- MetricsInfo mi(bv(), tmpfont, workWidth());
- tmpinset->metrics(mi, dim);
- maxwidth += dim.wid;
- maxasc = max(maxasc, dim.asc);
- maxdesc = max(maxdesc, dim.des);
-#else
maxwidth += tmpinset->width();
maxasc = max(maxasc, tmpinset->ascent());
maxdesc = max(maxdesc, tmpinset->descent());
-#endif
}
} else {
// Fall-back to normal case
- maxwidth += singleWidth(pit, pos, c);
+ maxwidth += singleWidth(pit, pos, c, font);
// And flush font cache
endPosOfFontSpan = 0;
}
maxasc += int(layoutasc * 2 / (2 + pit->getDepth()));
maxdesc += int(layoutdesc * 2 / (2 + pit->getDepth()));
- // calculate the new height of the text
- height -= rit->height();
-
rit->height(maxasc + maxdesc + labeladdon);
rit->baseline(maxasc + labeladdon);
-
- height += rit->height();
-
rit->top_of_text(rit->baseline() - font_metrics::maxAscent(font));
double x = 0;
- if (layout->margintype != MARGIN_RIGHT_ADDRESS_BOX) {
- // this IS needed
- rit->width(maxwidth);
- double dummy;
- prepareToPrint(pit, rit, x, dummy, dummy, dummy, false);
- }
rit->width(int(maxwidth + x));
if (inset_owner) {
width = max(0, workWidth());
void LyXText::charInserted()
{
- // Here we could call FinishUndo for every 20 characters inserted.
+ // Here we could call finishUndo for every 20 characters inserted.
// This is from my experience how emacs does it. (Lgb)
static unsigned int counter;
if (counter < 20) {
void LyXText::prepareToPrint(ParagraphList::iterator pit,
- RowList::iterator rit, double & x,
- double & fill_separator,
- double & fill_hfill,
- double & fill_label_hfill,
- bool bidi) const
+ RowList::iterator const rit) const
{
double w = rit->fill();
- fill_hfill = 0;
- fill_label_hfill = 0;
- fill_separator = 0;
- fill_label_hfill = 0;
+ double fill_hfill = 0;
+ double fill_label_hfill = 0;
+ double fill_separator = 0;
+ double x = 0;
bool const is_rtl =
pit->isRightToLeftPar(bv()->buffer()->params);
} else {
align = pit->params().align();
}
-
- // center displayed insets
InsetOld * inset = 0;
- if (rit->pos() < pit->size()
- && pit->isInset(rit->pos())
- && (inset = pit->getInset(rit->pos()))
- && (inset->display())) // || (inset->scroll() < 0)))
- align = (inset->lyxCode() == InsetOld::MATHMACRO_CODE)
- ? LYX_ALIGN_BLOCK : LYX_ALIGN_CENTER;
// ERT insets should always be LEFT ALIGNED on screen
inset = pit->inInset();
if (inset && inset->owner() &&
switch (align) {
case LYX_ALIGN_BLOCK:
- {
+ {
int const ns = numberOfSeparators(*pit, rit);
RowList::iterator next_row = boost::next(rit);
if (ns
&& next_row != pit->rows.end()
&& !pit->isNewline(next_row->pos() - 1)
- && !(pit->isInset(next_row->pos())
- && pit->getInset(next_row->pos())
- && pit->getInset(next_row->pos())->display())
) {
- fill_separator = w / ns;
+ fill_separator = w / ns;
} else if (is_rtl) {
x += w;
}
break;
}
}
- if (!bidi)
- return;
- computeBidiTables(pit, bv()->buffer(), rit);
+ computeBidiTables(pit, *bv()->buffer(), rit);
if (is_rtl) {
pos_type body_pos = pit->beginningOfBody();
pos_type last = lastPos(*pit, rit);
if (body_pos > 0 &&
- (body_pos - 1 > last ||
- !pit->isLineSeparator(body_pos - 1))) {
+ (body_pos - 1 > last ||
+ !pit->isLineSeparator(body_pos - 1))) {
x += font_metrics::width(layout->labelsep, getLabelFont(pit));
if (body_pos - 1 <= last)
x += fill_label_hfill;
}
}
+
+ rit->fill_hfill(fill_hfill);
+ rit->fill_label_hfill(fill_label_hfill);
+ rit->fill_separator(fill_separator);
+ rit->x(x);
}
cursorLeft(bv());
// the layout things can change the height of a row !
- setHeightOfRow(cursor.par(), cursorRow());
+ redoParagraph();
return;
}
}
// Pasting is not allowed, if the paragraphs have different
// layout. I think it is a real bug of all other
// word processors to allow it. It confuses the user.
- //Correction: Pasting is always allowed with standard-layout
+ // Correction: Pasting is always allowed with standard-layout
LyXTextClass const & tclass =
bv()->buffer()->params.getLyXTextClass();
RowList::iterator
LyXText::getRow(ParagraphList::iterator pit, pos_type pos) const
{
- RowList::iterator rit = pit->rows.begin();
- RowList::iterator end = pit->rows.end();
+ RowList::iterator rit = boost::prior(pit->rows.end());
+ RowList::iterator const begin = pit->rows.begin();
-#warning Why is this next thing needed? (Andre)
- while (rit != end
- && rit->pos() < pos
- && boost::next(rit) != end
- && boost::next(rit)->pos() <= pos)
- ++rit;
-
- return rit;
-}
-
-
-// returns pointer to a specified row
-RowList::iterator
-LyXText::getRow(ParagraphList::iterator pit, pos_type pos, int & y) const
-{
- y = 0;
-
- if (noRows())
- return firstRow();
-
- ParagraphList::iterator it = ownerParagraphs().begin();
- for ( ; it != pit; ++it) {
- RowList::iterator beg = it->rows.begin();
- RowList::iterator end = it->rows.end();
- for (RowList::iterator rit = beg; rit != end; ++rit)
- y += rit->height();
- }
-
- RowList::iterator rit = pit->rows.begin();
- RowList::iterator end = pit->rows.end();
- while (rit != end
- && rit->pos() < pos
- && boost::next(rit) != end
- && boost::next(rit)->pos() <= pos) {
- y += rit->height();
- ++rit;
- }
+ while (rit != begin && rit->pos() > pos)
+ --rit;
return rit;
}
// returns pointer to some fancy row 'below' specified row
RowList::iterator LyXText::cursorIRow() const
{
- int y = 0;
- return getRow(cursor.par(), cursor.pos(), y);
+ return getRow(cursor.par(), cursor.pos());
}
-RowList::iterator LyXText::getRowNearY(int & y,
+RowList::iterator LyXText::getRowNearY(int y,
ParagraphList::iterator & pit) const
{
- ParagraphList::iterator const end = ownerParagraphs().end();
//lyxerr << "getRowNearY: y " << y << endl;
- for (pit = ownerParagraphs().begin(); pit != end; ++pit) {
- RowList::iterator rit = pit->rows.begin();
- RowList::iterator rend = pit->rows.end();
+ pit = boost::prior(ownerParagraphs().end());
- for ( ; rit != rend; ++rit) {
- //rit->dump();
- if (rit->y() >= y) {
- if (rit != firstRow())
- previousRow(pit, rit);
- y = rit->y();
- return rit;
- }
- }
- }
+ RowList::iterator rit = lastRow();
+ RowList::iterator rbegin = firstRow();
-#if 1
- pit = ownerParagraphs().begin();
- y = 0;
- lyxerr << "row not found near " << y << " pit: " << &*pit << endl;
- return firstRow();
-#else
- pit = boost::prior(ownerParagraphs().end());
- lyxerr << "row not found near " << y << " pit: " << &*pit << endl;
- return lastRow();
-#endif
+ while (rit != rbegin && static_cast<int>(rit->y()) > y)
+ previousRow(pit, rit);
+
+ return rit;
}
void LyXText::nextRow(ParagraphList::iterator & pit,
RowList::iterator & rit) const
{
- if (boost::next(rit) != pit->rows.end()) {
- rit = boost::next(rit);
- } else {
+ ++rit;
+ if (rit == pit->rows.end()) {
++pit;
if (pit == ownerParagraphs().end())
- rit = boost::next(rit);
+ --pit;
else
rit = pit->rows.begin();
}
RowList::iterator & rit) const
{
if (rit != pit->rows.begin())
- rit = boost::prior(rit);
+ --rit;
else {
Assert(pit != ownerParagraphs().begin());
--pit;