X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext.C;h=8e68a70a32f797702cf157a8266ab2fa36d220dd;hb=fe390e9da1538e20eabbc98977d845295f8e563d;hp=e900b46d2a40af60bbe008a5c16d9c12fe67312e;hpb=25b275f182aafcfcdc7e0ada4f60a862e00c9442;p=lyx.git diff --git a/src/text.C b/src/text.C index e900b46d2a..8e68a70a32 100644 --- a/src/text.C +++ b/src/text.C @@ -30,9 +30,11 @@ #include "language.h" #include "ParagraphParameters.h" #include "undo_funcs.h" +#include "text_funcs.h" #include "WordLangTuple.h" #include "paragraph_funcs.h" #include "rowpainter.h" +#include "lyxrow_funcs.h" #include "insets/insettext.h" @@ -42,11 +44,17 @@ #include +using namespace lyx::support; + using std::max; using std::min; using std::endl; using std::pair; + using lyx::pos_type; +using lyx::word_location; + +using namespace bv_funcs; /// top, right, bottom pixel margin extern int const PAPER_MARGIN = 20; @@ -60,31 +68,35 @@ extern int bibitemMaxWidth(BufferView *, LyXFont const &); BufferView * LyXText::bv() { - lyx::Assert(bv_owner != 0); + Assert(bv_owner != 0); return bv_owner; } BufferView * LyXText::bv() const { - lyx::Assert(bv_owner != 0); + Assert(bv_owner != 0); return bv_owner; } -int LyXText::top_y() const +void LyXText::updateRowPositions() { - if (anchor_row_ == rows().end()) - return 0; - - int y = 0; - RowList::iterator rit = rows().begin(); - RowList::iterator end = rows().end(); - for (; rit != end && rit != anchor_row_; ++rit) { + RowList::iterator rend = rows().end(); + for (int y = 0; rit != rend ; ++rit) { + rit->y(y); y += rit->height(); } - return y + anchor_row_offset_; +} + + +int LyXText::top_y() const +{ + if (anchor_row_ == rowlist_.end()) + return 0; + + return anchor_row_->y() + anchor_row_offset_; } @@ -92,6 +104,13 @@ void LyXText::top_y(int newy) { if (rows().empty()) return; + + if (isInInset()) { + anchor_row_ = rows().begin(); + anchor_row_offset_ = newy; + return; + } + lyxerr[Debug::GUI] << "setting top y = " << newy << endl; int y = newy; @@ -117,8 +136,8 @@ void LyXText::anchor_row(RowList::iterator rit) anchor_row_ = rit; anchor_row_offset_ = old_y - top_y(); lyxerr[Debug::GUI] << "anchor_row(): changing reference to row: " - << &*anchor_row_ << " offset: " << anchor_row_offset_ - << endl; + << &*anchor_row_ << " offset: " + << anchor_row_offset_ << endl; } @@ -132,13 +151,15 @@ int LyXText::workWidth() const } -int LyXText::workWidth(Inset * inset) const +int LyXText::workWidth(Inset const * inset) const { - Paragraph * par = inset->parOwner(); - lyx::Assert(par); + ParagraphList::iterator par = std::find(ownerParagraphs().begin(), + ownerParagraphs().end(), + *inset->parOwner()); + //Assert(par); pos_type pos = par->getPositionOfInset(inset); - lyx::Assert(pos != -1); + Assert(pos != -1); LyXLayout_ptr const & layout = par->layout(); @@ -149,12 +170,12 @@ int LyXText::workWidth(Inset * inset) const Row dummyrow; dummyrow.par(par); dummyrow.pos(pos); - return workWidth() - leftMargin(&dummyrow); + return workWidth() - leftMargin(dummyrow); } else { int dummy_y; RowList::iterator row = getRow(par, pos, dummy_y); RowList::iterator frow = row; - RowList::iterator beg = rows().begin(); + RowList::iterator beg = rowlist_.begin(); while (frow != beg && frow->par() == boost::prior(frow)->par()) --frow; @@ -162,7 +183,7 @@ int LyXText::workWidth(Inset * inset) const // FIXME: I don't understand this code - jbl unsigned int maxw = 0; - while (!frow->isParEnd()) { + while (!isParEnd(*this, frow)) { if ((frow != row) && (maxw < frow->width())) maxw = frow->width(); ++frow; @@ -184,8 +205,9 @@ int LyXText::getRealCursorX() const } -unsigned char LyXText::transformChar(unsigned char c, Paragraph * par, - pos_type pos) const +#warning FIXME This function seems to belong outside of LyxText. +unsigned char LyXText::transformChar(unsigned char c, Paragraph const & par, + pos_type pos) const { if (!Encodings::is_arabic(c)) if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && IsDigit(c)) @@ -193,14 +215,18 @@ unsigned char LyXText::transformChar(unsigned char c, Paragraph * par, else return c; - unsigned char const prev_char = pos > 0 ? par->getChar(pos-1) : ' '; + unsigned char const prev_char = pos > 0 ? par.getChar(pos - 1) : ' '; unsigned char next_char = ' '; - for (pos_type i = pos+1; i < par->size(); ++i) - if (!Encodings::IsComposeChar_arabic(par->getChar(i))) { - next_char = par->getChar(i); + pos_type const par_size = par.size(); + + for (pos_type i = pos + 1; i < par_size; ++i) { + unsigned char const par_char = par.getChar(i); + if (!Encodings::IsComposeChar_arabic(par_char)) { + next_char = par_char; break; } + } if (Encodings::is_arabic(next_char)) { if (Encodings::is_arabic(prev_char) && @@ -242,24 +268,23 @@ unsigned char LyXText::transformChar(unsigned char c, Paragraph * par, // // Lgb -int LyXText::singleWidth(Paragraph * par, - pos_type pos) const +int LyXText::singleWidth(ParagraphList::iterator pit, pos_type pos) const { - if (pos >= par->size()) + if (pos >= pit->size()) return 0; - char const c = par->getChar(pos); - return singleWidth(par, pos, c); + char const c = pit->getChar(pos); + return singleWidth(pit, pos, c); } -int LyXText::singleWidth(Paragraph * par, +int LyXText::singleWidth(ParagraphList::iterator pit, pos_type pos, char c) const { - if (pos >= par->size()) + if (pos >= pit->size()) return 0; - LyXFont const font = getFont(bv()->buffer(), par, pos); + LyXFont const font = getFont(bv()->buffer(), pit, pos); // The most common case is handled first (Asger) if (IsPrintable(c)) { @@ -270,7 +295,7 @@ int LyXText::singleWidth(Paragraph * par, if (Encodings::IsComposeChar_arabic(c)) return 0; else - c = transformChar(c, par, pos); + c = transformChar(c, *pit, pos); } else if (font.language()->lang() == "hebrew" && Encodings::IsComposeChar_hebrew(c)) return 0; @@ -280,7 +305,7 @@ int LyXText::singleWidth(Paragraph * par, } if (c == Paragraph::META_INSET) { - Inset * tmpinset = par->getInset(pos); + Inset * tmpinset = pit->getInset(pos); if (tmpinset) { if (tmpinset->lyxCode() == Inset::HFILL_CODE) { // Because of the representation as vertical lines @@ -309,7 +334,7 @@ lyx::pos_type LyXText::log2vis(lyx::pos_type pos) const if (bidi_start == -1) return pos; else - return log2vis_list[pos-bidi_start]; + return log2vis_list[pos - bidi_start]; } @@ -318,7 +343,7 @@ lyx::pos_type LyXText::vis2log(lyx::pos_type pos) const if (bidi_start == -1) return pos; else - return vis2log_list[pos-bidi_start]; + return vis2log_list[pos - bidi_start]; } @@ -327,7 +352,7 @@ lyx::pos_type LyXText::bidi_level(lyx::pos_type pos) const if (bidi_start == -1) return 0; else - return bidi_levels[pos-bidi_start]; + return bidi_levels[pos - bidi_start]; } @@ -339,7 +364,7 @@ bool LyXText::bidi_InRange(lyx::pos_type pos) const void LyXText::computeBidiTables(Buffer const * buf, - Row const & row) const + RowList::iterator row) const { bidi_same_direction = true; if (!lyxrc.rtl_support) { @@ -347,15 +372,17 @@ void LyXText::computeBidiTables(Buffer const * buf, return; } - Inset * inset = row.par()->inInset(); + ParagraphList::iterator row_par = row->par(); + + Inset * inset = row_par->inInset(); if (inset && inset->owner() && inset->owner()->lyxCode() == Inset::ERT_CODE) { bidi_start = -1; return; } - bidi_start = row.pos(); - bidi_end = row.lastPrintablePos(); + bidi_start = row->pos(); + bidi_end = lastPrintablePos(*this, row); if (bidi_start > bidi_end) { bidi_start = -1; @@ -377,25 +404,25 @@ void LyXText::computeBidiTables(Buffer const * buf, pos_type stack[2]; bool const rtl_par = - row.par()->isRightToLeftPar(buf->params); + row_par->isRightToLeftPar(buf->params); int level = 0; bool rtl = false; bool rtl0 = false; - pos_type const body_pos = row.par()->beginningOfBody(); + pos_type const body_pos = row_par->beginningOfBody(); for (pos_type lpos = bidi_start; lpos <= bidi_end; ++lpos) { - bool is_space = row.par()->isLineSeparator(lpos); + bool is_space = row_par->isLineSeparator(lpos); pos_type const pos = (is_space && lpos + 1 <= bidi_end && - !row.par()->isLineSeparator(lpos + 1) && - !row.par()->isNewline(lpos + 1)) + !row_par->isLineSeparator(lpos + 1) && + !row_par->isNewline(lpos + 1)) ? lpos + 1 : lpos; - LyXFont font = row.par()->getFontSettings(buf->params, pos); + LyXFont font = row_par->getFontSettings(buf->params, pos); if (pos != lpos && 0 < lpos && rtl0 && font.isRightToLeft() && font.number() == LyXFont::ON && - row.par()->getFontSettings(buf->params, lpos - 1).number() + row_par->getFontSettings(buf->params, lpos - 1).number() == LyXFont::ON) { - font = row.par()->getFontSettings(buf->params, lpos); + font = row_par->getFontSettings(buf->params, lpos); is_space = false; } @@ -405,7 +432,7 @@ void LyXText::computeBidiTables(Buffer const * buf, int new_level; if (lpos == body_pos - 1 - && row.pos() < body_pos - 1 + && row->pos() < body_pos - 1 && is_space) { new_level = (rtl_par) ? 1 : 0; new_rtl = new_rtl0 = rtl_par; @@ -466,7 +493,7 @@ void LyXText::computeBidiTables(Buffer const * buf, // This method requires a previous call to ComputeBidiTables() -bool LyXText::isBoundary(Buffer const * buf, Paragraph * par, +bool LyXText::isBoundary(Buffer const * buf, Paragraph const & par, pos_type pos) const { if (!lyxrc.rtl_support || pos == 0) @@ -481,12 +508,12 @@ bool LyXText::isBoundary(Buffer const * buf, Paragraph * par, 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 * par, +bool LyXText::isBoundary(Buffer const * buf, Paragraph const & par, pos_type pos, LyXFont const & font) const { if (!lyxrc.rtl_support) @@ -495,24 +522,24 @@ bool LyXText::isBoundary(Buffer const * buf, Paragraph * par, 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(RowList::iterator rit) const +int LyXText::leftMargin(Row const & row) const { Inset * ins; - if (rit->pos() < rit->par()->size()) - if ((rit->par()->getChar(rit->pos()) == Paragraph::META_INSET) && - (ins = rit->par()->getInset(rit->pos())) && + if (row.pos() < row.par()->size()) + if ((row.par()->getChar(row.pos()) == Paragraph::META_INSET) && + (ins = row.par()->getInset(row.pos())) && (ins->needFullRow() || ins->display())) return LEFT_MARGIN; LyXTextClass const & tclass = bv()->buffer()->params.getLyXTextClass(); - LyXLayout_ptr const & layout = rit->par()->layout(); + LyXLayout_ptr const & layout = row.par()->layout(); string parindent = layout->parindent; @@ -523,39 +550,37 @@ int LyXText::leftMargin(RowList::iterator rit) const // this is the way, LyX handles the LaTeX-Environments. // I have had this idea very late, so it seems to be a // later added hack and this is true - if (!rit->par()->getDepth()) { - if (rit->par()->layout() == tclass.defaultLayout()) { + if (!row.par()->getDepth()) { + if (row.par()->layout() == tclass.defaultLayout()) { // find the previous same level paragraph - if (rit->par()->previous()) { - Paragraph * newpar = rit->par() - ->depthHook(rit->par()->getDepth()); - if (newpar && - newpar->layout()->nextnoindent) + if (row.par() != ownerParagraphs().begin()) { + ParagraphList::iterator newpit = + depthHook(row.par(), ownerParagraphs(), + row.par()->getDepth()); + if (newpit == row.par() && + newpit->layout()->nextnoindent) parindent.erase(); } } } else { // find the next level paragraph - Paragraph * newpar = rit->par()->outerHook(); + ParagraphList::iterator newpar = outerHook(row.par(), + ownerParagraphs()); - // make a corresponding row. Needed to call LeftMargin() + // make a corresponding row. Needed to call leftMargin() // check wether it is a sufficent paragraph - if (newpar && newpar->layout()->isEnvironment()) { + if (newpar != ownerParagraphs().end() && + newpar->layout()->isEnvironment()) { Row dummyrow; dummyrow.par(newpar); dummyrow.pos(newpar->size()); - x = leftMargin(&dummyrow); - } else { - // this is no longer an error, because this function - // is used to clear impossible depths after changing - // a layout. Since there is always a redo, - // LeftMargin() is always called - rit->par()->params().depth(0); + x = leftMargin(dummyrow); } - if (newpar && rit->par()->layout() == tclass.defaultLayout()) { + if (newpar != ownerParagraphs().end() && + row.par()->layout() == tclass.defaultLayout()) { if (newpar->params().noindent()) parindent.erase(); else { @@ -565,17 +590,17 @@ int LyXText::leftMargin(RowList::iterator rit) const } } - LyXFont const labelfont = getLabelFont(bv()->buffer(), rit->par()); + LyXFont const labelfont = getLabelFont(bv()->buffer(), row.par()); switch (layout->margintype) { case MARGIN_DYNAMIC: if (!layout->leftmargin.empty()) { x += font_metrics::signedWidth(layout->leftmargin, tclass.defaultfont()); } - if (!rit->par()->getLabelstring().empty()) { + if (!row.par()->getLabelstring().empty()) { x += font_metrics::signedWidth(layout->labelindent, labelfont); - x += font_metrics::width(rit->par()->getLabelstring(), + x += font_metrics::width(row.par()->getLabelstring(), labelfont); x += font_metrics::width(layout->labelsep, labelfont); } @@ -583,9 +608,9 @@ int LyXText::leftMargin(RowList::iterator rit) const case MARGIN_MANUAL: x += font_metrics::signedWidth(layout->labelindent, labelfont); // The width of an empty par, even with manual label, should be 0 - if (!rit->par()->empty() && rit->pos() >= rit->par()->beginningOfBody()) { - if (!rit->par()->getLabelWidthString().empty()) { - x += font_metrics::width(rit->par()->getLabelWidthString(), + if (!row.par()->empty() && row.pos() >= row.par()->beginningOfBody()) { + if (!row.par()->getLabelWidthString().empty()) { + x += font_metrics::width(row.par()->getLabelWidthString(), labelfont); x += font_metrics::width(layout->labelsep, labelfont); } @@ -593,23 +618,23 @@ int LyXText::leftMargin(RowList::iterator rit) const break; case MARGIN_STATIC: x += font_metrics::signedWidth(layout->leftmargin, tclass.defaultfont()) * 4 - / (rit->par()->getDepth() + 4); + / (row.par()->getDepth() + 4); break; case MARGIN_FIRST_DYNAMIC: if (layout->labeltype == LABEL_MANUAL) { - if (rit->pos() >= rit->par()->beginningOfBody()) { + if (row.pos() >= row.par()->beginningOfBody()) { x += font_metrics::signedWidth(layout->leftmargin, labelfont); } else { x += font_metrics::signedWidth(layout->labelindent, labelfont); } - } else if (rit->pos() + } else if (row.pos() // Special case to fix problems with // theorems (JMarc) || (layout->labeltype == LABEL_STATIC && layout->latextype == LATEX_ENVIRONMENT - && ! rit->par()->isFirstInSequence())) { + && !isFirstInSequence(row.par(), ownerParagraphs()))) { x += font_metrics::signedWidth(layout->leftmargin, labelfont); } else if (layout->labeltype != LABEL_TOP_ENVIRONMENT @@ -619,7 +644,7 @@ int LyXText::leftMargin(RowList::iterator rit) const x += font_metrics::signedWidth(layout->labelindent, labelfont); x += font_metrics::width(layout->labelsep, labelfont); - x += font_metrics::width(rit->par()->getLabelstring(), + x += font_metrics::width(row.par()->getLabelstring(), labelfont); } break; @@ -631,14 +656,14 @@ int LyXText::leftMargin(RowList::iterator rit) const // are *NOT* allowed in the LaTeX realisation of this layout. // find the first row of this paragraph - RowList::iterator tmprit = rit; - while (tmprit != rows().begin() - && boost::prior(tmprit)->par() == rit->par()) - --tmprit; + RowList::iterator tmprit = rowlist_.begin(); + while (tmprit != rowlist_.end() + && tmprit->par() != row.par()) + ++tmprit; int minfill = tmprit->fill(); - while (boost::next(tmprit) != rows().end() && - boost::next(tmprit)->par() == rit->par()) { + while (boost::next(tmprit) != rowlist_.end() && + boost::next(tmprit)->par() == row.par()) { ++tmprit; if (tmprit->fill() < minfill) minfill = tmprit->fill(); @@ -652,36 +677,36 @@ int LyXText::leftMargin(RowList::iterator rit) const } if ((workWidth() > 0) && - !rit->par()->params().leftIndent().zero()) + !row.par()->params().leftIndent().zero()) { - LyXLength const len = rit->par()->params().leftIndent(); + LyXLength const len = row.par()->params().leftIndent(); int const tw = inset_owner ? inset_owner->latexTextWidth(bv()) : workWidth(); x += len.inPixels(tw); } - LyXAlignment align; // wrong type + LyXAlignment align; - if (rit->par()->params().align() == LYX_ALIGN_LAYOUT) + if (row.par()->params().align() == LYX_ALIGN_LAYOUT) align = layout->align; else - align = rit->par()->params().align(); + align = row.par()->params().align(); // set the correct parindent - if (rit->pos() == 0) { + if (row.pos() == 0) { if ((layout->labeltype == LABEL_NO_LABEL || layout->labeltype == LABEL_TOP_ENVIRONMENT || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT || (layout->labeltype == LABEL_STATIC && layout->latextype == LATEX_ENVIRONMENT - && ! rit->par()->isFirstInSequence())) + && !isFirstInSequence(row.par(), ownerParagraphs()))) && align == LYX_ALIGN_BLOCK - && !rit->par()->params().noindent() + && !row.par()->params().noindent() // in tabulars and ert paragraphs are never indented! - && (!rit->par()->inInset() || !rit->par()->inInset()->owner() || - (rit->par()->inInset()->owner()->lyxCode() != Inset::TABULAR_CODE && - rit->par()->inInset()->owner()->lyxCode() != Inset::ERT_CODE)) - && (rit->par()->layout() != tclass.defaultLayout() || + && (!row.par()->inInset() || !row.par()->inInset()->owner() || + (row.par()->inInset()->owner()->lyxCode() != Inset::TABULAR_CODE && + row.par()->inInset()->owner()->lyxCode() != Inset::ERT_CODE)) + && (row.par()->layout() != tclass.defaultLayout() || bv()->buffer()->params.paragraph_separation == BufferParams::PARSEP_INDENT)) { x += font_metrics::signedWidth(parindent, @@ -713,37 +738,6 @@ int LyXText::rightMargin(Buffer const & buf, Row const & row) const + font_metrics::signedWidth(tclass.rightmargin(), tclass.defaultfont()); - // this is the way, LyX handles the LaTeX-Environments. - // I have had this idea very late, so it seems to be a - // later added hack and this is true - if (row.par()->getDepth()) { - // find the next level paragraph - - Paragraph const * newpar = row.par(); - - do { - newpar = newpar->previous(); - } while (newpar - && newpar->getDepth() >= row.par()->getDepth()); - - // make a corresponding row. Needed to call LeftMargin() - - // check wether it is a sufficent paragraph - if (newpar && newpar->layout()->isEnvironment()) { - Row dummyrow; - dummyrow.par(const_cast(newpar)); - dummyrow.pos(0); - x = rightMargin(buf, dummyrow); - } else { - // this is no longer an error, because this function - // is used to clear impossible depths after changing - // a layout. Since there is always a redo, - // LeftMargin() is always called - row.par()->params().depth(0); - } - } - - //lyxerr << "rightmargin: " << layout->rightmargin << endl; x += font_metrics::signedWidth(layout->rightmargin, tclass.defaultfont()) * 4 / (row.par()->getDepth() + 4); @@ -757,7 +751,7 @@ int LyXText::labelEnd(Row const & row) const Row tmprow = row; tmprow.pos(row.par()->size()); // return the beginning of the body - return leftMargin(&tmprow); + return leftMargin(tmprow); } // LabelEnd is only needed if the layout @@ -769,23 +763,22 @@ int LyXText::labelEnd(Row const & row) const namespace { // this needs special handling - only newlines count as a break point -pos_type addressBreakPoint(pos_type i, Paragraph * par) +pos_type addressBreakPoint(pos_type i, Paragraph const & par) { - for (; i < par->size(); ++i) { - if (par->isNewline(i)) + for (; i < par.size(); ++i) { + if (par.isNewline(i)) return i; } - return par->size(); + return par.size(); } }; -pos_type -LyXText::rowBreakPoint(Row const & row) const +pos_type LyXText::rowBreakPoint(Row const & row) const { - Paragraph * par = row.par(); + ParagraphList::iterator pit = row.par(); // maximum pixel width of a row. int width = workWidth() - rightMargin(*bv()->buffer(), row); @@ -793,16 +786,16 @@ LyXText::rowBreakPoint(Row const & row) const // inset->textWidth() returns -1 via workWidth(), // but why ? if (width < 0) - return par->size(); + return pit->size(); - LyXLayout_ptr const & layout = par->layout(); + LyXLayout_ptr const & layout = pit->layout(); if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) - return addressBreakPoint(row.pos(), par); + return addressBreakPoint(row.pos(), *pit); pos_type const pos = row.pos(); - pos_type const body_pos = par->beginningOfBody(); - pos_type const last = par->size(); + pos_type const body_pos = pit->beginningOfBody(); + pos_type const last = pit->size(); pos_type point = last; if (pos == last) @@ -812,40 +805,43 @@ LyXText::rowBreakPoint(Row const & row) const // or the end of the par, then choose the possible break // nearest that. - int const left = leftMargin(const_cast(&row)); + int const left = leftMargin(row); int x = left; // pixel width since last breakpoint int chunkwidth = 0; + bool fullrow = false; pos_type i = pos; for (; i < last; ++i) { - - if (par->isNewline(i)) { + if (pit->isNewline(i)) { point = i; break; } - char const c = par->getChar(i); + char const c = pit->getChar(i); - int thiswidth = singleWidth(par, i, c); + int thiswidth; // add the auto-hfill from label end to the body if (body_pos && i == body_pos) { - thiswidth += font_metrics::width(layout->labelsep, - getLabelFont(bv()->buffer(), par)); - if (par->isLineSeparator(i - 1)) - thiswidth -= singleWidth(par, i - 1); + thiswidth = font_metrics::width(layout->labelsep, + getLabelFont(bv()->buffer(), pit)); + if (pit->isLineSeparator(i - 1)) + thiswidth -= singleWidth(pit, i - 1); int left_margin = labelEnd(row); - if (thiswidth < left_margin) - thiswidth = left_margin; + if (thiswidth + x < left_margin) + thiswidth = left_margin - x; + thiswidth += singleWidth(pit, i, c); + } else { + thiswidth = singleWidth(pit, i, c); } x += thiswidth; chunkwidth += thiswidth; - Inset * in = par->isInset(i) ? par->getInset(i) : 0; - bool fullrow = (in && (in->display() || in->needFullRow())); + Inset * 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 @@ -863,7 +859,7 @@ LyXText::rowBreakPoint(Row const & row) const if (!in || in->isChar()) { // some insets are line separators too - if (par->isLineSeparator(i)) { + if (pit->isLineSeparator(i)) { point = i; chunkwidth = 0; } @@ -877,7 +873,7 @@ LyXText::rowBreakPoint(Row const & row) const if (i == pos) { if (pos < last - 1) { point = i; - if (par->isLineSeparator(i + 1)) + if (pit->isLineSeparator(i + 1)) ++point; } else { // to avoid extra rows @@ -886,7 +882,8 @@ LyXText::rowBreakPoint(Row const & row) const } else { point = i - 1; } - break; + + return point; } if (point == last && x >= width) { @@ -898,8 +895,10 @@ LyXText::rowBreakPoint(Row const & row) const point = last; } - // manual labels cannot be broken in LaTeX - if (body_pos && point < body_pos) + // 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) point = body_pos - 1; return point; @@ -907,52 +906,66 @@ LyXText::rowBreakPoint(Row const & row) const // returns the minimum space a row needs on the screen in pixel -int LyXText::fill(Row & row, int paper_width) const +int LyXText::fill(RowList::iterator row, int paper_width) const { if (paper_width < 0) return 0; int w; // get the pure distance - pos_type const last = row.lastPrintablePos(); + pos_type const last = lastPrintablePos(*this, row); + + ParagraphList::iterator pit = row->par(); + LyXLayout_ptr const & layout = pit->layout(); // special handling of the right address boxes - if (row.par()->layout()->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - int const tmpfill = row.fill(); - row.fill(0); // the minfill in MarginLeft() - w = leftMargin(&row); - row.fill(tmpfill); + if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) { + int const tmpfill = row->fill(); + row->fill(0); // the minfill in MarginLeft() + w = leftMargin(*row); + row->fill(tmpfill); } else - w = leftMargin(&row); + w = leftMargin(*row); - Paragraph * par = row.par(); - LyXLayout_ptr const & layout = par->layout(); - - pos_type const body_pos = par->beginningOfBody(); - pos_type i = row.pos(); + pos_type const body_pos = pit->beginningOfBody(); + pos_type i = row->pos(); while (i <= last) { if (body_pos > 0 && i == body_pos) { - w += font_metrics::width(layout->labelsep, getLabelFont(bv()->buffer(), par)); - if (par->isLineSeparator(i - 1)) - w -= singleWidth(par, i - 1); - int left_margin = labelEnd(row); + w += font_metrics::width(layout->labelsep, getLabelFont(bv()->buffer(), pit)); + if (pit->isLineSeparator(i - 1)) + w -= singleWidth(pit, i - 1); + int left_margin = labelEnd(*row); if (w < left_margin) w = left_margin; } - w += singleWidth(par, i); + w += singleWidth(pit, i); ++i; } if (body_pos > 0 && body_pos > last) { - w += font_metrics::width(layout->labelsep, getLabelFont(bv()->buffer(), par)); - if (last >= 0 && par->isLineSeparator(last)) - w -= singleWidth(par, last); - int const left_margin = labelEnd(row); + w += font_metrics::width(layout->labelsep, getLabelFont(bv()->buffer(), pit)); + if (last >= 0 && pit->isLineSeparator(last)) + w -= singleWidth(pit, last); + int const left_margin = labelEnd(*row); if (w < left_margin) w = left_margin; } - int const fill = paper_width - w - rightMargin(*bv()->buffer(), row); + int const fill = paper_width - w - rightMargin(*bv()->buffer(), *row); + + // If this case happens, it means that our calculation + // of the widths of the chars when we do rowBreakPoint() + // went wrong for some reason. Typically in list bodies. + // Things just about hobble on anyway, though you'll end + // up with a "fill_separator" less than zero, which corresponds + // to inter-word spacing being too small. Hopefully this problem + // will die when the label hacks die. + if (lyxerr.debugging() && fill < 0) { + lyxerr[Debug::GUI] << "Eek, fill() was < 0: " << fill + << " w " << w << " paper_width " << paper_width + << " right margin " << rightMargin(*bv()->buffer(), *row) << endl; + } + return fill; } @@ -960,29 +973,31 @@ int LyXText::fill(Row & row, int paper_width) const // returns the minimum space a manual label needs on the screen in pixel int LyXText::labelFill(Row const & row) const { - pos_type last = row.par()->beginningOfBody(); + ParagraphList::iterator pit = row.par(); - lyx::Assert(last > 0); + pos_type last = pit->beginningOfBody(); + + Assert(last > 0); // -1 because a label ends either with a space that is in the label, // or with the beginning of a footnote that is outside the label. --last; // a separator at this end does not count - if (row.par()->isLineSeparator(last)) + if (pit->isLineSeparator(last)) --last; int w = 0; pos_type i = row.pos(); while (i <= last) { - w += singleWidth(row.par(), i); + w += singleWidth(pit, i); ++i; } int fill = 0; - string const & labwidstr = row.par()->params().labelWidthString(); + string const & labwidstr = pit->params().labelWidthString(); if (!labwidstr.empty()) { - LyXFont const labfont = getLabelFont(bv()->buffer(), row.par()); + LyXFont const labfont = getLabelFont(bv()->buffer(), pit); int const labwidth = font_metrics::width(labwidstr, labfont); fill = max(labwidth - w, 0); } @@ -1002,9 +1017,9 @@ LColor::color LyXText::backgroundColor() const void LyXText::setHeightOfRow(RowList::iterator rit) { + Assert(rit != rows().end()); + // get the maximum ascent and the maximum descent - int asc = 0; - int desc = 0; float layoutasc = 0; float layoutdesc = 0; float tmptop = 0; @@ -1018,25 +1033,24 @@ void LyXText::setHeightOfRow(RowList::iterator rit) // Correction: only the fontsize count. The other properties // are taken from the layoutfont. Nicer on the screen :) - Paragraph * par = rit->par(); - Paragraph * firstpar = par; + ParagraphList::iterator pit = rit->par(); - LyXLayout_ptr const & layout = firstpar->layout(); + LyXLayout_ptr const & layout = pit->layout(); // as max get the first character of this row then it can increase but not // decrease the height. Just some point to start with so we don't have to // do the assignment below too often. - LyXFont font = getFont(bv()->buffer(), par, rit->pos()); + LyXFont font = getFont(bv()->buffer(), pit, rit->pos()); LyXFont::FONT_SIZE const tmpsize = font.size(); - font = getLayoutFont(bv()->buffer(), par); + font = getLayoutFont(bv()->buffer(), pit); LyXFont::FONT_SIZE const size = font.size(); font.setSize(tmpsize); - LyXFont labelfont = getLabelFont(bv()->buffer(), par); + LyXFont labelfont = getLabelFont(bv()->buffer(), pit); float spacing_val = 1.0; - if (!rit->par()->params().spacing().isDefault()) { - spacing_val = rit->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { spacing_val = bv()->buffer()->params.spacing.getValue(); } @@ -1049,29 +1063,29 @@ void LyXText::setHeightOfRow(RowList::iterator rit) layout->spacing.getValue() * spacing_val); - pos_type const pos_end = rit->lastPos(); + pos_type const pos_end = lastPos(*this, rit); int labeladdon = 0; int maxwidth = 0; - if (!rit->par()->empty()) { + if (!pit->empty()) { // Check if any insets are larger for (pos_type pos = rit->pos(); pos <= pos_end; ++pos) { - if (rit->par()->isInset(pos)) { - tmpfont = getFont(bv()->buffer(), rit->par(), pos); - tmpinset = rit->par()->getInset(pos); + if (pit->isInset(pos)) { + tmpfont = getFont(bv()->buffer(), pit, pos); + tmpinset = pit->getInset(pos); if (tmpinset) { #if 1 // this is needed for deep update on initialitation #warning inset->update FIXME tmpinset->update(bv()); #endif - asc = tmpinset->ascent(bv(), tmpfont); - desc = tmpinset->descent(bv(), tmpfont); maxwidth += tmpinset->width(bv(), tmpfont); - maxasc = max(maxasc, asc); - maxdesc = max(maxdesc, desc); + maxasc = max(maxasc, + tmpinset->ascent(bv(), tmpfont)); + maxdesc = max(maxdesc, + tmpinset->descent(bv(), tmpfont)); } } else { - maxwidth += singleWidth(rit->par(), pos); + maxwidth += singleWidth(pit, pos); } } } @@ -1080,16 +1094,11 @@ void LyXText::setHeightOfRow(RowList::iterator rit) // This is not completely correct, but we can live with the small, // cosmetic error for now. LyXFont::FONT_SIZE maxsize = - rit->par()->highestFontInRange(rit->pos(), pos_end, size); + pit->highestFontInRange(rit->pos(), pos_end, size); if (maxsize > font.size()) { font.setSize(maxsize); - - asc = font_metrics::maxAscent(font); - desc = font_metrics::maxDescent(font); - if (asc > maxasc) - maxasc = asc; - if (desc > maxdesc) - maxdesc = desc; + maxasc = max(maxasc, font_metrics::maxAscent(font)); + maxdesc = max(maxdesc, font_metrics::maxDescent(font)); } // This is nicer with box insets: @@ -1099,20 +1108,20 @@ void LyXText::setHeightOfRow(RowList::iterator rit) rit->ascent_of_text(maxasc); // is it a top line? - if (!rit->pos() && (rit->par() == firstpar)) { + if (!rit->pos()) { // some parksips VERY EASY IMPLEMENTATION if (bv()->buffer()->params.paragraph_separation == BufferParams::PARSEP_SKIP) { if (layout->isParagraph() - && firstpar->getDepth() == 0 - && firstpar->previous()) + && pit->getDepth() == 0 + && pit != ownerParagraphs().begin()) { maxasc += bv()->buffer()->params.getDefSkip().inPixels(*bv()); - } else if (firstpar->previous() && - firstpar->previous()->layout()->isParagraph() && - firstpar->previous()->getDepth() == 0) + } else if (pit != ownerParagraphs().begin() && + boost::prior(pit)->layout()->isParagraph() && + boost::prior(pit)->getDepth() == 0) { // is it right to use defskip here too? (AS) maxasc += bv()->buffer()->params.getDefSkip().inPixels(*bv()); @@ -1120,23 +1129,23 @@ void LyXText::setHeightOfRow(RowList::iterator rit) } // the top margin - if (!rit->par()->previous() && !isInInset()) + if (pit == ownerParagraphs().begin() && !isInInset()) maxasc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxasc += getLengthMarkerHeight(*bv(), firstpar->params().spaceTop()); + maxasc += getLengthMarkerHeight(*bv(), pit->params().spaceTop()); // do not forget the DTP-lines! // there height depends on the font of the nearest character - if (firstpar->params().lineTop()) + if (pit->params().lineTop()) maxasc += 2 * font_metrics::ascent('x', getFont(bv()->buffer(), - firstpar, 0)); + pit, 0)); // and now the pagebreaks - if (firstpar->params().pagebreakTop()) + if (pit->params().pagebreakTop()) maxasc += 3 * defaultRowHeight(); - if (firstpar->params().startOfAppendix()) + if (pit->params().startOfAppendix()) maxasc += 3 * defaultRowHeight(); // This is special code for the chapter, since the label of this @@ -1145,8 +1154,8 @@ void LyXText::setHeightOfRow(RowList::iterator rit) && bv()->buffer()->params.secnumdepth >= 0) { float spacing_val = 1.0; - if (!rit->par()->params().spacing().isDefault()) { - spacing_val = rit->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { spacing_val = bv()->buffer()->params.spacing.getValue(); } @@ -1163,12 +1172,12 @@ void LyXText::setHeightOfRow(RowList::iterator rit) if ((layout->labeltype == LABEL_TOP_ENVIRONMENT || layout->labeltype == LABEL_BIBLIO || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) - && rit->par()->isFirstInSequence() - && !rit->par()->getLabelstring().empty()) + && isFirstInSequence(pit, ownerParagraphs()) + && !pit->getLabelstring().empty()) { float spacing_val = 1.0; - if (!rit->par()->params().spacing().isDefault()) { - spacing_val = rit->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { spacing_val = bv()->buffer()->params.spacing.getValue(); } @@ -1184,44 +1193,41 @@ void LyXText::setHeightOfRow(RowList::iterator rit) + layout->labelbottomsep * defaultRowHeight()); } - // and now the layout spaces, for example before and after a section, - // or between the items of a itemize or enumerate environment - - if (!firstpar->params().pagebreakTop()) { - Paragraph * prev = rit->par()->previous(); - if (prev) - prev = rit->par()->depthHook(rit->par()->getDepth()); - if (prev && prev->layout() == firstpar->layout() && - prev->getDepth() == firstpar->getDepth() && - prev->getLabelWidthString() == firstpar->getLabelWidthString()) + // And now the layout spaces, for example before and after + // a section, or between the items of a itemize or enumerate + // environment. + + if (!pit->params().pagebreakTop()) { + ParagraphList::iterator prev = + depthHook(pit, ownerParagraphs(), + pit->getDepth()); + if (prev != pit && prev->layout() == layout && + prev->getDepth() == pit->getDepth() && + prev->getLabelWidthString() == pit->getLabelWidthString()) { layoutasc = (layout->itemsep * defaultRowHeight()); } else if (rit != rows().begin()) { tmptop = layout->topsep; - if (boost::prior(rit)->par()->getDepth() >= rit->par()->getDepth()) + if (boost::prior(pit)->getDepth() >= pit->getDepth()) tmptop -= boost::prior(rit)->par()->layout()->bottomsep; if (tmptop > 0) layoutasc = (tmptop * defaultRowHeight()); - } else if (rit->par()->params().lineTop()) { + } else if (pit->params().lineTop()) { tmptop = layout->topsep; if (tmptop > 0) layoutasc = (tmptop * defaultRowHeight()); } - prev = rit->par()->outerHook(); - if (prev) { + prev = outerHook(pit, ownerParagraphs()); + if (prev != ownerParagraphs().end()) { maxasc += int(prev->layout()->parsep * defaultRowHeight()); - } else { - if (firstpar->previous() && - firstpar->previous()->getDepth() == 0 && - firstpar->previous()->layout() != - firstpar->layout()) - { - // avoid parsep - } else if (firstpar->previous()) { + } else if (pit != ownerParagraphs().begin()) { + ParagraphList::iterator prior_pit = boost::prior(pit); + if (prior_pit->getDepth() != 0 || + prior_pit->layout() == layout) { maxasc += int(layout->parsep * defaultRowHeight()); } } @@ -1229,64 +1235,65 @@ void LyXText::setHeightOfRow(RowList::iterator rit) } // is it a bottom line? - if (rit->par() == par - && (boost::next(rit) == rows().end() || - boost::next(rit)->par() != rit->par())) { + RowList::iterator next_rit = boost::next(rit); + if (next_rit == rows().end() || + next_rit->par() != pit) { // the bottom margin - if (!par->next() && !isInInset()) + ParagraphList::iterator nextpit = boost::next(pit); + if (nextpit == ownerParagraphs().end() && + !isInInset()) maxdesc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxdesc += getLengthMarkerHeight(*bv(), firstpar->params().spaceBottom()); + maxdesc += getLengthMarkerHeight(*bv(), pit->params().spaceBottom()); // do not forget the DTP-lines! // there height depends on the font of the nearest character - if (firstpar->params().lineBottom()) + if (pit->params().lineBottom()) maxdesc += 2 * font_metrics::ascent('x', getFont(bv()->buffer(), - par, - max(pos_type(0), par->size() - 1))); + pit, + max(pos_type(0), pit->size() - 1))); // and now the pagebreaks - if (firstpar->params().pagebreakBottom()) + if (pit->params().pagebreakBottom()) maxdesc += 3 * defaultRowHeight(); // and now the layout spaces, for example before and after // a section, or between the items of a itemize or enumerate // environment - if (!firstpar->params().pagebreakBottom() - && rit->par()->next()) { - Paragraph * nextpar = rit->par()->next(); - Paragraph * comparepar = rit->par(); + if (!pit->params().pagebreakBottom() + && nextpit != ownerParagraphs().end()) { + ParagraphList::iterator comparepit = pit; float usual = 0; float unusual = 0; - if (comparepar->getDepth() > nextpar->getDepth()) { - usual = (comparepar->layout()->bottomsep * defaultRowHeight()); - comparepar = comparepar->depthHook(nextpar->getDepth()); - if (comparepar->layout()!= nextpar->layout() - || nextpar->getLabelWidthString() != - comparepar->getLabelWidthString()) + if (comparepit->getDepth() > nextpit->getDepth()) { + usual = (comparepit->layout()->bottomsep * defaultRowHeight()); + comparepit = depthHook(comparepit, ownerParagraphs(), nextpit->getDepth()); + if (comparepit->layout()!= nextpit->layout() + || nextpit->getLabelWidthString() != + comparepit->getLabelWidthString()) { - unusual = (comparepar->layout()->bottomsep * defaultRowHeight()); + unusual = (comparepit->layout()->bottomsep * defaultRowHeight()); } if (unusual > usual) layoutdesc = unusual; else layoutdesc = usual; - } else if (comparepar->getDepth() == nextpar->getDepth()) { + } else if (comparepit->getDepth() == nextpit->getDepth()) { - if (comparepar->layout() != nextpar->layout() - || nextpar->getLabelWidthString() != - comparepar->getLabelWidthString()) - layoutdesc = int(comparepar->layout()->bottomsep * defaultRowHeight()); + if (comparepit->layout() != nextpit->layout() + || nextpit->getLabelWidthString() != + comparepit->getLabelWidthString()) + layoutdesc = int(comparepit->layout()->bottomsep * defaultRowHeight()); } } } // incalculate the layout spaces - maxasc += int(layoutasc * 2 / (2 + firstpar->getDepth())); - maxdesc += int(layoutdesc * 2 / (2 + firstpar->getDepth())); + maxasc += int(layoutasc * 2 / (2 + pit->getDepth())); + maxdesc += int(layoutdesc * 2 / (2 + pit->getDepth())); // calculate the new height of the text height -= rit->height(); @@ -1322,7 +1329,7 @@ void LyXText::setHeightOfRow(RowList::iterator rit) // start at the implicit given position void LyXText::appendParagraph(RowList::iterator rowit) { - lyx::Assert(rowit != rowlist_.end()); + Assert(rowit != rowlist_.end()); pos_type const last = rowit->par()->size(); bool done = false; @@ -1334,8 +1341,8 @@ void LyXText::appendParagraph(RowList::iterator rowit) if (z < last) { ++z; - rowit = rowlist_.insert(rowit->next(), - new Row(rowit->par(), z)); + Row newrow(rowit->par(), z); + rowit = rowlist_.insert(boost::next(rowit), newrow); } else { done = true; } @@ -1343,8 +1350,8 @@ void LyXText::appendParagraph(RowList::iterator rowit) // Set the dimensions of the row // fixed fill setting now by calling inset->update() in // SingleWidth when needed! - tmprow->fill(fill(*tmprow, workWidth())); - setHeightOfRow(&*tmprow); + tmprow->fill(fill(tmprow, workWidth())); + setHeightOfRow(tmprow); } while (!done); } @@ -1352,7 +1359,7 @@ void LyXText::appendParagraph(RowList::iterator rowit) void LyXText::breakAgain(RowList::iterator rit) { - lyx::Assert(rit != rows().end()); + Assert(rit != rows().end()); bool not_ready = true; @@ -1362,12 +1369,15 @@ void LyXText::breakAgain(RowList::iterator rit) RowList::iterator end = rows().end(); if (z < rit->par()->size()) { - if (boost::next(rit) == end || - (boost::next(rit) != end && - boost::next(rit)->par() != rit->par())) { + RowList::iterator next_rit = boost::next(rit); + + if (next_rit == end || + (next_rit != end && + next_rit->par() != rit->par())) { // insert a new row ++z; - rit = rowlist_.insert(boost::next(rit), new Row(rit->par(), z)); + Row newrow(rit->par(), z); + rit = rowlist_.insert(next_rit, newrow); } else { ++rit; ++z; @@ -1381,7 +1391,8 @@ void LyXText::breakAgain(RowList::iterator rit) // if there are some rows too much, delete them // only if you broke the whole paragraph! RowList::iterator tmprit2 = rit; - while (boost::next(tmprit2) != end && boost::next(tmprit2)->par() == rit->par()) { + while (boost::next(tmprit2) != end + && boost::next(tmprit2)->par() == rit->par()) { ++tmprit2; } while (tmprit2 != rit) { @@ -1392,7 +1403,7 @@ void LyXText::breakAgain(RowList::iterator rit) } // set the dimensions of the row - tmprit->fill(fill(*tmprit, workWidth())); + tmprit->fill(fill(tmprit, workWidth())); setHeightOfRow(tmprit); } while (not_ready); } @@ -1401,17 +1412,22 @@ void LyXText::breakAgain(RowList::iterator rit) // this is just a little changed version of break again void LyXText::breakAgainOneRow(RowList::iterator rit) { - lyx::Assert(rit != rows().end()); + Assert(rit != rows().end()); pos_type z = rowBreakPoint(*rit); RowList::iterator tmprit = rit; + RowList::iterator end = rows().end(); if (z < rit->par()->size()) { - if (boost::next(rit) == rows().end() - || (boost::next(rit) != rows().end() && boost::next(rit)->par() != rit->par())) { + RowList::iterator next_rit = boost::next(rit); + + if (next_rit == end || + (next_rit != end && + next_rit->par() != rit->par())) { // insert a new row ++z; - rit = rowlist_.insert(boost::next(rit), new Row(rit->par(), z)); + Row newrow(rit->par(), z); + rit = rowlist_.insert(next_rit, newrow); } else { ++rit; ++z; @@ -1422,7 +1438,7 @@ void LyXText::breakAgainOneRow(RowList::iterator rit) // if there are some rows too much, delete them // only if you broke the whole paragraph! RowList::iterator tmprit2 = rit; - while (boost::next(tmprit2) != rows().end() + while (boost::next(tmprit2) != end && boost::next(tmprit2)->par() == rit->par()) { ++tmprit2; } @@ -1433,7 +1449,7 @@ void LyXText::breakAgainOneRow(RowList::iterator rit) } // set the dimensions of the row - tmprit->fill(fill(*tmprit, workWidth())); + tmprit->fill(fill(tmprit, workWidth())); setHeightOfRow(tmprit); } @@ -1450,13 +1466,12 @@ void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout) LyXLayout_ptr const & layout = cursor.par()->layout(); // this is only allowed, if the current paragraph is not empty or caption - // and if it has not the keepempty flag aktive - if (cursor.par()->empty() - && layout->labeltype != LABEL_SENSITIVE - && !layout->keepempty) + // and if it has not the keepempty flag active + if (cursor.par()->empty() && !cursor.par()->allowEmpty() + && layout->labeltype != LABEL_SENSITIVE) return; - setUndo(bv(), Undo::FINISH, cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::FINISH, cursor.par()); // Always break behind a space // @@ -1476,7 +1491,7 @@ void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout) // breakParagraph call should return a bool if it inserts the // paragraph before or behind and we should react on that one // but we can fix this in 1.3.0 (Jug 20020509) - bool const isempty = (layout->keepempty && cursor.par()->empty()); + bool const isempty = (cursor.par()->allowEmpty() && cursor.par()->empty()); ::breakParagraph(bv()->buffer()->params, paragraphs, cursor.par(), cursor.pos(), keep_layout); @@ -1487,59 +1502,62 @@ void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout) cursor.par()->applyLayout(tclass.defaultLayout()); else // set to standard-layout - cursor.par()->next()->applyLayout(tclass.defaultLayout()); + boost::next(cursor.par())->applyLayout(tclass.defaultLayout()); } // if the cursor is at the beginning of a row without prior newline, // move one row up! // This touches only the screen-update. Otherwise we would may have // an empty row on the screen - if (cursor.pos() && !cursor.row()->par()->isNewline(cursor.row()->pos() - 1) - && cursor.row()->pos() == cursor.pos()) + if (cursor.pos() && cursorRow()->pos() == cursor.pos() + && !cursorRow()->par()->isNewline(cursor.pos() - 1)) { cursorLeft(bv()); } - int y = cursor.y() - cursor.row()->baseline(); + int y = cursor.y() - cursorRow()->baseline(); // Do not forget the special right address boxes if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - Row * r = cursor.row(); - while (r->previous() && r->previous()->par() == r->par()) { - r = r->previous(); + RowList::iterator r = cursorRow(); + RowList::iterator beg = rows().begin(); + + while (r != beg && boost::prior(r)->par() == r->par()) { + --r; y -= r->height(); } } postPaint(y); - removeParagraph(cursor.row()); + removeParagraph(cursorRow()); // set the dimensions of the cursor row - cursor.row()->fill(fill(*cursor.row(), workWidth())); + cursorRow()->fill(fill(cursorRow(), workWidth())); - setHeightOfRow(cursor.row()); + setHeightOfRow(cursorRow()); #warning Trouble Point! (Lgb) // When ::breakParagraph is called from within an inset we must // ensure that the correct ParagraphList is used. Today that is not // the case and the Buffer::paragraphs is used. Not good. (Lgb) - while (!cursor.par()->next()->empty() - && cursor.par()->next()->isNewline(0)) - cursor.par()->next()->erase(0); + ParagraphList::iterator next_par = boost::next(cursor.par()); + + while (!next_par->empty() && next_par->isNewline(0)) + next_par->erase(0); - insertParagraph(cursor.par()->next(), cursor.row()->next()); + insertParagraph(next_par, boost::next(cursorRow())); updateCounters(); // This check is necessary. Otherwise the new empty paragraph will // be deleted automatically. And it is more friendly for the user! if (cursor.pos() || isempty) - setCursor(cursor.par()->next(), 0); + setCursor(next_par, 0); else setCursor(cursor.par(), 0); - if (cursor.row()->next()) - breakAgain(cursor.row()->next()); + if (boost::next(cursorRow()) != rows().end()) + breakAgain(boost::next(cursorRow())); need_break_row = rows().end(); } @@ -1549,7 +1567,7 @@ void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout) void LyXText::redoParagraph() { clearSelection(); - redoParagraphs(cursor, cursor.par()->next()); + redoParagraphs(cursor, boost::next(cursor.par())); setCursorIntern(cursor.par(), cursor.pos()); } @@ -1558,13 +1576,13 @@ void LyXText::redoParagraph() // same Paragraph one to the right and make a rebreak void LyXText::insertChar(char c) { - setUndo(bv(), Undo::INSERT, cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::INSERT, cursor.par()); // When the free-spacing option is set for the current layout, // disable the double-space checking - bool const freeSpacing = cursor.row()->par()->layout()->free_spacing || - cursor.row()->par()->isFreeSpacing(); + bool const freeSpacing = cursorRow()->par()->layout()->free_spacing || + cursorRow()->par()->isFreeSpacing(); if (lyxrc.auto_number) { static string const number_operators = "+-/*"; @@ -1658,17 +1676,17 @@ void LyXText::insertChar(char c) } // the display inset stuff - if (cursor.row()->pos() < cursor.row()->par()->size() - && cursor.row()->par()->isInset(cursor.row()->pos())) { - Inset * inset = cursor.row()->par()->getInset(cursor.row()->pos()); + if (cursorRow()->pos() < cursorRow()->par()->size() + && cursorRow()->par()->isInset(cursorRow()->pos())) { + Inset * inset = cursorRow()->par()->getInset(cursorRow()->pos()); if (inset && (inset->display() || inset->needFullRow())) { // force a new break - cursor.row()->fill(-1); // to force a new break + cursorRow()->fill(-1); // to force a new break } } // get the cursor row fist - Row * row = cursor.row(); + RowList::iterator row = cursorRow(); int y = cursor.y() - row->baseline(); if (c != Paragraph::META_INSET) { // Here case LyXText::InsertInset already insertet the character @@ -1678,34 +1696,36 @@ void LyXText::insertChar(char c) if (!jumped_over_space) { // refresh the positions - Row * tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); + RowList::iterator tmprow = row; + while (boost::next(tmprow) != rows().end() && + boost::next(tmprow)->par() == row->par()) { + ++tmprow; tmprow->pos(tmprow->pos() + 1); } } // Is there a break one row above - if (row->previous() && row->previous()->par() == row->par() + if (row != rows().begin() && + boost::prior(row)->par() == row->par() && (cursor.par()->isLineSeparator(cursor.pos()) || cursor.par()->isNewline(cursor.pos()) || ((cursor.pos() + 1 < cursor.par()->size()) && cursor.par()->isInset(cursor.pos() + 1)) - || cursor.row()->fill() == -1)) + || cursorRow()->fill() == -1)) { - pos_type z = rowBreakPoint(*row->previous()); + pos_type z = rowBreakPoint(*boost::prior(row)); if (z >= row->pos()) { row->pos(z + 1); // set the dimensions of the row above - row->previous()->fill(fill( - *row->previous(), + boost::prior(row)->fill(fill( + boost::prior(row), workWidth())); - setHeightOfRow(row->previous()); + setHeightOfRow(boost::prior(row)); - y -= row->previous()->height(); + y -= boost::prior(row)->height(); postPaint(y); @@ -1717,8 +1737,10 @@ void LyXText::insertChar(char c) false, cursor.boundary()); // cursor MUST be in row now. - if (row->next() && row->next()->par() == row->par()) - need_break_row = row->next(); + RowList::iterator next_row = boost::next(row); + if (next_row != rows().end() && + next_row->par() == row->par()) + need_break_row = next_row; else need_break_row = rows().end(); @@ -1736,17 +1758,24 @@ void LyXText::insertChar(char c) if (row->fill() >= 0) { // needed because a newline will set fill to -1. Otherwise // we would not get a rebreak! - row->fill(fill(*row, workWidth())); + row->fill(fill(row, workWidth())); } if (c == Paragraph::META_INSET || row->fill() < 0) { postPaint(y); breakAgainOneRow(row); + + RowList::iterator next_row = boost::next(row); + // will the cursor be in another row now? - if (row->lastPos() <= cursor.pos() + 1 && row->next()) { - if (row->next() && row->next()->par() == row->par()) + if (lastPos(*this, row) <= cursor.pos() + 1 && + next_row != rows().end()) { + if (next_row != rows().end() && + next_row->par() == row->par()) { // this should always be true - row = row->next(); + ++row; + } + breakAgainOneRow(row); } current_font = rawtmpfont; @@ -1754,12 +1783,16 @@ void LyXText::insertChar(char c) setCursor(cursor.par(), cursor.pos() + 1, false, cursor.boundary()); - if (isBoundary(bv()->buffer(), cursor.par(), cursor.pos()) + if (isBoundary(bv()->buffer(), *cursor.par(), cursor.pos()) != cursor.boundary()) setCursor(cursor.par(), cursor.pos(), false, !cursor.boundary()); - if (row->next() && row->next()->par() == row->par()) - need_break_row = row->next(); + + next_row = boost::next(row); + + if (next_row != rows().end() && + next_row->par() == row->par()) + need_break_row = next_row; else need_break_row = rows().end(); } else { @@ -1799,7 +1832,7 @@ void LyXText::insertChar(char c) void LyXText::charInserted() { // Here we could call FinishUndo for every 20 characters inserted. - // This is from my experience how emacs does it. + // This is from my experience how emacs does it. (Lgb) static unsigned int counter; if (counter < 20) { ++counter; @@ -1816,47 +1849,46 @@ void LyXText::prepareToPrint(RowList::iterator rit, float & x, float & fill_label_hfill, bool bidi) const { - float nlh; - float ns; - float w = rit->fill(); fill_hfill = 0; fill_label_hfill = 0; fill_separator = 0; fill_label_hfill = 0; + ParagraphList::iterator pit = rit->par(); + bool const is_rtl = - rit->par()->isRightToLeftPar(bv()->buffer()->params); + pit->isRightToLeftPar(bv()->buffer()->params); if (is_rtl) { x = (workWidth() > 0) ? rightMargin(*bv()->buffer(), *rit) : 0; } else x = (workWidth() > 0) - ? leftMargin(rit) : 0; + ? leftMargin(*rit) : 0; // is there a manual margin with a manual label - LyXLayout_ptr const & layout = rit->par()->layout(); + LyXLayout_ptr const & layout = pit->layout(); if (layout->margintype == MARGIN_MANUAL && layout->labeltype == LABEL_MANUAL) { /// We might have real hfills in the label part - nlh = rit->numberOfLabelHfills(); + float nlh = numberOfLabelHfills(*this, rit); // A manual label par (e.g. List) has an auto-hfill // between the label text and the body of the // paragraph too. // But we don't want to do this auto hfill if the par // is empty. - if (!rit->par()->empty()) + if (!pit->empty()) ++nlh; - if (nlh && !rit->par()->getLabelWidthString().empty()) { + if (nlh && !pit->getLabelWidthString().empty()) { fill_label_hfill = labelFill(*rit) / nlh; } } // are there any hfills in the row? - float const nh = rit->numberOfHfills(); + float const nh = numberOfHfills(*this, rit); if (nh) { if (w > 0) @@ -1868,22 +1900,22 @@ void LyXText::prepareToPrint(RowList::iterator rit, float & x, // is it block, flushleft or flushright? // set x how you need it int align; - if (rit->par()->params().align() == LYX_ALIGN_LAYOUT) { + if (pit->params().align() == LYX_ALIGN_LAYOUT) { align = layout->align; } else { - align = rit->par()->params().align(); + align = pit->params().align(); } // center displayed insets - Inset * inset; - if (rit->pos() < rit->par()->size() - && rit->par()->isInset(rit->pos()) - && (inset = rit->par()->getInset(rit->pos())) + Inset * inset = 0; + if (rit->pos() < pit->size() + && pit->isInset(rit->pos()) + && (inset = pit->getInset(rit->pos())) && (inset->display())) // || (inset->scroll() < 0))) align = (inset->lyxCode() == Inset::MATHMACRO_CODE) ? LYX_ALIGN_BLOCK : LYX_ALIGN_CENTER; // ERT insets should always be LEFT ALIGNED on screen - inset = rit->par()->inInset(); + inset = pit->inInset(); if (inset && inset->owner() && inset->owner()->lyxCode() == Inset::ERT_CODE) { @@ -1892,20 +1924,24 @@ void LyXText::prepareToPrint(RowList::iterator rit, float & x, switch (align) { case LYX_ALIGN_BLOCK: - ns = rit->numberOfSeparators(); - if (ns && boost::next(rit) != rows().end() && - boost::next(rit)->par() == rit->par() && - !(boost::next(rit)->par()->isNewline(boost::next(rit)->pos() - 1)) - && !(boost::next(rit)->par()->isInset(boost::next(rit)->pos()) - && boost::next(rit)->par()->getInset(boost::next(rit)->pos()) - && boost::next(rit)->par()->getInset(boost::next(rit)->pos())->display()) - ) - { + { + float const ns = numberOfSeparators(*this, rit); + RowList::iterator next_row = boost::next(rit); + ParagraphList::iterator next_pit = next_row->par(); + + if (ns && next_row != rowlist_.end() && + next_pit == pit && + !(next_pit->isNewline(next_row->pos() - 1)) + && !(next_pit->isInset(next_row->pos()) && + next_pit->getInset(next_row->pos()) && + next_pit->getInset(next_row->pos())->display()) + ) { fill_separator = w / ns; } else if (is_rtl) { x += w; } break; + } case LYX_ALIGN_RIGHT: x += w; break; @@ -1917,16 +1953,17 @@ void LyXText::prepareToPrint(RowList::iterator rit, float & x, if (!bidi) return; - computeBidiTables(bv()->buffer(), *rit); + computeBidiTables(bv()->buffer(), rit); if (is_rtl) { - pos_type body_pos = rit->par()->beginningOfBody(); - pos_type last = rit->lastPos(); + pos_type body_pos = pit->beginningOfBody(); + pos_type last = lastPos(*this, rit); if (body_pos > 0 && (body_pos - 1 > last || - !rit->par()->isLineSeparator(body_pos - 1))) { + !pit->isLineSeparator(body_pos - 1))) { x += font_metrics::width(layout->labelsep, - getLabelFont(bv()->buffer(), rit->par())); + getLabelFont(bv()->buffer(), + pit)); if (body_pos - 1 <= last) x += fill_label_hfill; } @@ -1943,51 +1980,8 @@ void LyXText::prepareToPrint(RowList::iterator rit, float & x, void LyXText::cursorRightOneWord() { - // treat floats, HFills and Insets as words - LyXCursor tmpcursor = cursor; - // CHECK See comment on top of text.C - - if (tmpcursor.pos() == tmpcursor.par()->size() - && tmpcursor.par()->next()) { - tmpcursor.par(tmpcursor.par()->next()); - tmpcursor.pos(0); - } else { - int steps = 0; - - // Skip through initial nonword stuff. - while (tmpcursor.pos() < tmpcursor.par()->size() && - ! tmpcursor.par()->isWord(tmpcursor.pos())) { - // printf("Current pos1 %d", tmpcursor.pos()) ; - tmpcursor.pos(tmpcursor.pos() + 1); - ++steps; - } - // Advance through word. - while (tmpcursor.pos() < tmpcursor.par()->size() && - tmpcursor.par()->isWord(tmpcursor.pos())) { - // printf("Current pos2 %d", tmpcursor.pos()) ; - tmpcursor.pos(tmpcursor.pos() + 1); - ++steps; - } - } - setCursor(tmpcursor.par(), tmpcursor.pos()); -} - - -void LyXText::cursorTab() -{ - LyXCursor tmpcursor = cursor; - while (tmpcursor.pos() < tmpcursor.par()->size() - && !tmpcursor.par()->isNewline(tmpcursor.pos())) - tmpcursor.pos(tmpcursor.pos() + 1); - - if (tmpcursor.pos() == tmpcursor.par()->size()) { - if (tmpcursor.par()->next()) { - tmpcursor.par(tmpcursor.par()->next()); - tmpcursor.pos(0); - } - } else - tmpcursor.pos(tmpcursor.pos() + 1); - setCursor(tmpcursor.par(), tmpcursor.pos()); + ::cursorRightOneWord(cursor, ownerParagraphs()); + setCursor(cursor.par(), cursor.pos()); } @@ -1996,96 +1990,16 @@ void LyXText::cursorTab() void LyXText::cursorLeftOneWord() { LyXCursor tmpcursor = cursor; - cursorLeftOneWord(tmpcursor); + ::cursorLeftOneWord(tmpcursor, ownerParagraphs()); setCursor(tmpcursor.par(), tmpcursor.pos()); } -void LyXText::cursorLeftOneWord(LyXCursor & cur) -{ - // treat HFills, floats and Insets as words - cur = cursor; - while (cur.pos() - && (cur.par()->isSeparator(cur.pos() - 1) - || cur.par()->isKomma(cur.pos() - 1) - || cur.par()->isNewline(cur.pos() - 1)) - && !(cur.par()->isHfill(cur.pos() - 1) - || cur.par()->isInset(cur.pos() - 1))) - cur.pos(cur.pos() - 1); - - if (cur.pos() - && (cur.par()->isInset(cur.pos() - 1) - || cur.par()->isHfill(cur.pos() - 1))) { - cur.pos(cur.pos() - 1); - } else if (!cur.pos()) { - if (cur.par()->previous()) { - cur.par(cur.par()->previous()); - cur.pos(cur.par()->size()); - } - } else { // Here, cur != 0 - while (cur.pos() > 0 && - cur.par()->isWord(cur.pos() - 1)) - cur.pos(cur.pos() - 1); - } -} - - -// Select current word. This depends on behaviour of -// CursorLeftOneWord(), so it is patched as well. -void LyXText::getWord(LyXCursor & from, LyXCursor & to, - word_location const loc) -{ - // first put the cursor where we wana start to select the word - from = cursor; - switch (loc) { - case WHOLE_WORD_STRICT: - if (cursor.pos() == 0 || cursor.pos() == cursor.par()->size() - || cursor.par()->isSeparator(cursor.pos()) - || cursor.par()->isKomma(cursor.pos()) - || cursor.par()->isNewline(cursor.pos()) - || cursor.par()->isSeparator(cursor.pos() - 1) - || cursor.par()->isKomma(cursor.pos() - 1) - || cursor.par()->isNewline(cursor.pos() - 1)) { - to = from; - return; - } - // no break here, we go to the next - - case WHOLE_WORD: - // Move cursor to the beginning, when not already there. - if (from.pos() && !from.par()->isSeparator(from.pos() - 1) - && !(from.par()->isKomma(from.pos() - 1) - || from.par()->isNewline(from.pos() - 1))) - cursorLeftOneWord(from); - break; - case PREVIOUS_WORD: - // always move the cursor to the beginning of previous word - cursorLeftOneWord(from); - break; - case NEXT_WORD: - lyxerr << "LyXText::getWord: NEXT_WORD not implemented yet\n"; - break; - case PARTIAL_WORD: - break; - } - to = from; - while (to.pos() < to.par()->size() - && !to.par()->isSeparator(to.pos()) - && !to.par()->isKomma(to.pos()) - && !to.par()->isNewline(to.pos()) - && !to.par()->isHfill(to.pos()) - && !to.par()->isInset(to.pos())) - { - to.pos(to.pos() + 1); - } -} - - void LyXText::selectWord(word_location loc) { - LyXCursor from; + LyXCursor from = cursor; LyXCursor to; - getWord(from, to, loc); + ::getWord(from, to, loc, ownerParagraphs()); if (cursor != from) setCursor(from.par(), from.pos()); if (to == from) @@ -2113,16 +2027,14 @@ void LyXText::acceptChange() if (!selection.set() && cursor.par()->size()) return; - bv()->hideCursor(); - if (selection.start.par() == selection.end.par()) { LyXCursor & startc = selection.start; LyXCursor & endc = selection.end; - setUndo(bv(), Undo::INSERT, startc.par(), startc.par()->next()); + setUndo(bv(), Undo::INSERT, startc.par()); startc.par()->acceptChange(startc.pos(), endc.pos()); finishUndo(); clearSelection(); - redoParagraphs(startc, startc.par()->next()); + redoParagraphs(startc, boost::next(startc.par())); setCursorIntern(startc.par(), 0); } #warning handle multi par selection @@ -2134,16 +2046,14 @@ void LyXText::rejectChange() if (!selection.set() && cursor.par()->size()) return; - bv()->hideCursor(); - if (selection.start.par() == selection.end.par()) { LyXCursor & startc = selection.start; LyXCursor & endc = selection.end; - setUndo(bv(), Undo::INSERT, startc.par(), startc.par()->next()); + setUndo(bv(), Undo::INSERT, startc.par()); startc.par()->rejectChange(startc.pos(), endc.pos()); finishUndo(); clearSelection(); - redoParagraphs(startc, startc.par()->next()); + redoParagraphs(startc, boost::next(startc.par())); setCursorIntern(startc.par(), 0); } #warning handle multi par selection @@ -2164,43 +2074,43 @@ LyXText::selectNextWordToSpellcheck(float & value) } // we have to go on checking so move cursor to the next char if (cursor.pos() == cursor.par()->size()) { - if (!cursor.par()->next()) + if (boost::next(cursor.par()) == ownerParagraphs().end()) return word; - cursor.par(cursor.par()->next()); + cursor.par(boost::next(cursor.par())); cursor.pos(0); } else cursor.pos(cursor.pos() + 1); } - Paragraph * tmppar = cursor.par(); + ParagraphList::iterator tmppit = cursor.par(); // If this is not the very first word, skip rest of // current word because we are probably in the middle // of a word if there is text here. - if (cursor.pos() || cursor.par()->previous()) { + if (cursor.pos() || cursor.par() != ownerParagraphs().begin()) { while (cursor.pos() < cursor.par()->size() && cursor.par()->isLetter(cursor.pos())) cursor.pos(cursor.pos() + 1); } // Now, skip until we have real text (will jump paragraphs) - while (1) { - Paragraph * cpar(cursor.par()); + while (true) { + ParagraphList::iterator cpit = cursor.par(); pos_type const cpos(cursor.pos()); - if (cpos == cpar->size()) { - if (cpar->next()) { - cursor.par(cpar->next()); + if (cpos == cpit->size()) { + if (boost::next(cpit) != ownerParagraphs().end()) { + cursor.par(boost::next(cpit)); cursor.pos(0); continue; } break; } - bool const is_bad_inset(cpar->isInset(cpos) - && !cpar->getInset(cpos)->allowSpellcheck()); + bool const is_good_inset = cpit->isInset(cpos) + && cpit->getInset(cpos)->allowSpellcheck(); - if (cpar->isLetter(cpos) && !isDeletedText(*cpar, cpos) - && !is_bad_inset) + if (!isDeletedText(*cpit, cpos) + && (is_good_inset || cpit->isLetter(cpos))) break; cursor.pos(cpos + 1); @@ -2210,14 +2120,15 @@ LyXText::selectNextWordToSpellcheck(float & value) if (cursor.pos() < cursor.par()->size() && cursor.par()->isInset(cursor.pos())) { // lock the inset! - cursor.par()->getInset(cursor.pos())->edit(bv()); + FuncRequest cmd(bv(), LFUN_INSET_EDIT, "left"); + cursor.par()->getInset(cursor.pos())->localDispatch(cmd); // now call us again to do the above trick // but obviously we have to start from down below ;) return bv()->text->selectNextWordToSpellcheck(value); } // Update the value if we changed paragraphs - if (cursor.par() != tmppar) { + if (cursor.par() != tmppit) { setCursor(cursor.par(), cursor.pos()); value = float(cursor.y())/float(height); } @@ -2280,7 +2191,6 @@ void LyXText::deleteWordForward() cursorRight(bv()); else { LyXCursor tmpcursor = cursor; - tmpcursor.row(0); // ?? selection.set(true); // to avoid deletion cursorRightOneWord(); setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); @@ -2301,7 +2211,6 @@ void LyXText::deleteWordBackward() cursorLeft(bv()); else { LyXCursor tmpcursor = cursor; - tmpcursor.row(0); // ?? selection.set(true); // to avoid deletion cursorLeftOneWord(); setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); @@ -2323,7 +2232,6 @@ void LyXText::deleteLineForward() LyXCursor tmpcursor = cursor; // We can't store the row over a regular setCursor // so we set it to 0 and reset it afterwards. - tmpcursor.row(0); // ?? selection.set(true); // to avoid deletion cursorEnd(); setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); @@ -2349,24 +2257,24 @@ void LyXText::changeCase(LyXText::TextCase action) from = selection.start; to = selection.end; } else { - getWord(from, to, PARTIAL_WORD); + from = cursor; + ::getWord(from, to, lyx::PARTIAL_WORD, ownerParagraphs()); setCursor(to.par(), to.pos() + 1); } - lyx::Assert(from <= to); - - setUndo(bv(), Undo::FINISH, from.par(), to.par()->next()); + setUndo(bv(), Undo::FINISH, from.par(), to.par()); pos_type pos = from.pos(); - Paragraph * par = from.par(); + ParagraphList::iterator pit = from.par(); - while (par && (pos != to.pos() || par != to.par())) { - if (pos == par->size()) { - par = par->next(); + while (pit != ownerParagraphs().end() && + (pos != to.pos() || pit != to.par())) { + if (pos == pit->size()) { + ++pit; pos = 0; continue; } - unsigned char c = par->getChar(pos); + unsigned char c = pit->getChar(pos); if (!IsInsetChar(c)) { switch (action) { case text_lowercase: @@ -2382,49 +2290,14 @@ void LyXText::changeCase(LyXText::TextCase action) } } #warning changes - par->setChar(pos, c); - checkParagraph(par, pos); + pit->setChar(pos, c); + checkParagraph(pit, pos); ++pos; } - if (to.row() != from.row()) - postPaint(from.y() - from.row()->baseline()); -} - - -void LyXText::transposeChars() -{ - Paragraph * tmppar = cursor.par(); - - setUndo(bv(), Undo::FINISH, tmppar, tmppar->next()); - - pos_type tmppos = cursor.pos(); - - // First decide if it is possible to transpose at all - - if (tmppos == 0 || tmppos == tmppar->size()) - return; - - if (isDeletedText(*tmppar, tmppos - 1) - || isDeletedText(*tmppar, tmppos)) - return; - - unsigned char c1 = tmppar->getChar(tmppos); - unsigned char c2 = tmppar->getChar(tmppos - 1); - - // We should have an implementation that handles insets - // as well, but that will have to come later. (Lgb) - if (c1 == Paragraph::META_INSET || c2 == Paragraph::META_INSET) - return; - - bool const erased = tmppar->erase(tmppos - 1, tmppos + 1); - pos_type const ipos(erased ? tmppos - 1 : tmppos + 1); - - tmppar->insertChar(ipos, c1); - tmppar->insertChar(ipos + 1, c2); - - checkParagraph(tmppar, tmppos); + if (getRow(to) != getRow(from)) + postPaint(from.y() - getRow(from)->baseline()); } @@ -2434,8 +2307,9 @@ void LyXText::Delete() LyXCursor old_cursor = cursor; int const old_cur_par_id = old_cursor.par()->id(); - int const old_cur_par_prev_id = old_cursor.par()->previous() ? - old_cursor.par()->previous()->id() : -1; + int const old_cur_par_prev_id = + (old_cursor.par() != ownerParagraphs().begin() ? + boost::prior(old_cursor.par())->id() : -1); // just move to the right cursorRight(bv()); @@ -2446,7 +2320,7 @@ void LyXText::Delete() // and that can very well delete the par or par->previous in // old_cursor. Will a solution where we compare paragraph id's //work better? - if ((cursor.par()->previous() ? cursor.par()->previous()->id() : -1) + if ((cursor.par() != ownerParagraphs().begin() ? boost::prior(cursor.par())->id() : -1) == old_cur_par_prev_id && cursor.par()->id() != old_cur_par_id) { // delete-empty-paragraph-mechanism has done it @@ -2458,8 +2332,7 @@ void LyXText::Delete() LyXCursor tmpcursor = cursor; // to make sure undo gets the right cursor position cursor = old_cursor; - setUndo(bv(), Undo::DELETE, - cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::DELETE, cursor.par()); cursor = tmpcursor; backspace(); } @@ -2492,45 +2365,46 @@ void LyXText::backspace() // left and let the DeleteEmptyParagraphMechanism handle the actual deletion // of the paragraph. - if (cursor.par()->previous()) { - Paragraph * tmppar = cursor.par()->previous(); - if (cursor.par()->layout() == tmppar->layout() - && cursor.par()->getAlign() == tmppar->getAlign()) { + if (cursor.par() != ownerParagraphs().begin()) { + ParagraphList::iterator tmppit = boost::prior(cursor.par()); + if (cursor.par()->layout() == tmppit->layout() + && cursor.par()->getAlign() == tmppit->getAlign()) { // Inherit bottom DTD from the paragraph below. // (the one we are deleting) - tmppar->params().lineBottom(cursor.par()->params().lineBottom()); - tmppar->params().spaceBottom(cursor.par()->params().spaceBottom()); - tmppar->params().pagebreakBottom(cursor.par()->params().pagebreakBottom()); + tmppit->params().lineBottom(cursor.par()->params().lineBottom()); + tmppit->params().spaceBottom(cursor.par()->params().spaceBottom()); + tmppit->params().pagebreakBottom(cursor.par()->params().pagebreakBottom()); } cursorLeft(bv()); // the layout things can change the height of a row ! - int const tmpheight = cursor.row()->height(); - setHeightOfRow(cursor.row()); - if (cursor.row()->height() != tmpheight) { - postPaint(cursor.y() - cursor.row()->baseline()); + int const tmpheight = cursorRow()->height(); + setHeightOfRow(cursorRow()); + if (cursorRow()->height() != tmpheight) { + postPaint(cursor.y() - cursorRow()->baseline()); } return; } } - if (cursor.par()->previous()) { + if (cursor.par() != ownerParagraphs().begin()) { setUndo(bv(), Undo::DELETE, - cursor.par()->previous(), cursor.par()->next()); + boost::prior(cursor.par()), + cursor.par()); } - Paragraph * tmppar = cursor.par(); - Row * tmprow = cursor.row(); + ParagraphList::iterator tmppit = cursor.par(); + RowList::iterator tmprow = cursorRow(); // We used to do cursorLeftIntern() here, but it is // not a good idea since it triggers the auto-delete // mechanism. So we do a cursorLeftIntern()-lite, // without the dreaded mechanism. (JMarc) - if (cursor.par()->previous()) { + if (cursor.par() != ownerParagraphs().begin()) { // steps into the above paragraph. - setCursorIntern(cursor.par()->previous(), - cursor.par()->previous()->size(), + setCursorIntern(boost::prior(cursor.par()), + boost::prior(cursor.par())->size(), false); } @@ -2546,10 +2420,10 @@ void LyXText::backspace() LyXTextClass const & tclass = bv()->buffer()->params.getLyXTextClass(); - if (cursor.par() != tmppar - && (cursor.par()->layout() == tmppar->layout() - || tmppar->layout() == tclass.defaultLayout()) - && cursor.par()->getAlign() == tmppar->getAlign()) { + if (cursor.par() != tmppit + && (cursor.par()->layout() == tmppit->layout() + || tmppit->layout() == tclass.defaultLayout()) + && cursor.par()->getAlign() == tmppit->getAlign()) { removeParagraph(tmprow); removeRow(tmprow); mergeParagraph(bv()->buffer()->params, bv()->buffer()->paragraphs, cursor.par()); @@ -2563,7 +2437,7 @@ void LyXText::backspace() if (cursor.pos()) cursor.pos(cursor.pos() - 1); - postPaint(cursor.y() - cursor.row()->baseline()); + postPaint(cursor.y() - cursorRow()->baseline()); // remove the lost paragraph // This one is not safe, since the paragraph that the tmprow and the @@ -2574,7 +2448,7 @@ void LyXText::backspace() //RemoveRow(tmprow); // This rebuilds the rows. - appendParagraph(cursor.row()); + appendParagraph(cursorRow()); updateCounters(); // the row may have changed, block, hfills etc. @@ -2583,8 +2457,7 @@ void LyXText::backspace() } else { // this is the code for a normal backspace, not pasting // any paragraphs - setUndo(bv(), Undo::DELETE, - cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::DELETE, cursor.par()); // We used to do cursorLeftIntern() here, but it is // not a good idea since it triggers the auto-delete // mechanism. So we do a cursorLeftIntern()-lite, @@ -2603,12 +2476,12 @@ void LyXText::backspace() } } - Row * row = cursor.row(); + RowList::iterator row = cursorRow(); int y = cursor.y() - row->baseline(); pos_type z; // remember that a space at the end of a row doesnt count // when calculating the fill - if (cursor.pos() < row->lastPos() || + if (cursor.pos() < lastPos(*this, row) || !cursor.par()->isLineSeparator(cursor.pos())) { row->fill(row->fill() + singleWidth( cursor.par(), @@ -2620,9 +2493,10 @@ void LyXText::backspace() if (cursor.pos() && cursor.par()->isNewline(cursor.pos())) { cursor.par()->erase(cursor.pos()); // refresh the positions - Row * tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); + RowList::iterator tmprow = row; + while (boost::next(tmprow) != rows().end() && + boost::next(tmprow)->par() == row->par()) { + ++tmprow; tmprow->pos(tmprow->pos() - 1); } if (cursor.par()->isLineSeparator(cursor.pos() - 1)) @@ -2635,8 +2509,9 @@ void LyXText::backspace() cursor.pos(), current_font); // refresh the positions tmprow = row; - while (tmprow->next() && tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); + while (boost::next(tmprow) != rows().end() && + boost::next(tmprow)->par() == row->par()) { + ++tmprow; tmprow->pos(tmprow->pos() + 1); } } @@ -2644,10 +2519,10 @@ void LyXText::backspace() cursor.par()->erase(cursor.pos()); // refresh the positions - Row * tmprow = row; - while (tmprow->next() - && tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); + RowList::iterator tmprow = row; + while (boost::next(tmprow) != rows().end() && + boost::next(tmprow)->par() == row->par()) { + ++tmprow; tmprow->pos(tmprow->pos() - 1); } @@ -2659,21 +2534,21 @@ void LyXText::backspace() cursor.par()->erase(cursor.pos()); // refresh the positions tmprow = row; - while (tmprow->next() && - tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); + while (boost::next(tmprow) != rows().end() && + boost::next(tmprow)->par() == row->par()) { + ++tmprow; tmprow->pos(tmprow->pos() - 1); } } } // is there a break one row above - if (row->previous() && row->previous()->par() == row->par()) { - z = rowBreakPoint(*row->previous()); + if (row != rows().begin() && boost::prior(row)->par() == row->par()) { + z = rowBreakPoint(*boost::prior(row)); if (z >= row->pos()) { row->pos(z + 1); - Row * tmprow = row->previous(); + RowList::iterator tmprow = boost::prior(row); // maybe the current row is now empty if (row->pos() >= row->par()->size()) { @@ -2682,15 +2557,16 @@ void LyXText::backspace() need_break_row = rows().end(); } else { breakAgainOneRow(row); - if (row->next() && row->next()->par() == row->par()) - need_break_row = row->next(); + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par()) + need_break_row = boost::next(row); else need_break_row = rows().end(); } // set the dimensions of the row above y -= tmprow->height(); - tmprow->fill(fill(*tmprow, workWidth())); + tmprow->fill(fill(tmprow, workWidth())); setHeightOfRow(tmprow); postPaint(y); @@ -2709,36 +2585,39 @@ void LyXText::backspace() } // break the cursor row again - if (row->next() && row->next()->par() == row->par() && - (row->lastPos() == row->par()->size() - 1 || - rowBreakPoint(*row) != row->lastPos())) { + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par() && + (lastPos(*this, row) == row->par()->size() - 1 || + rowBreakPoint(*row) != lastPos(*this, row))) { // it can happen that a paragraph loses one row // without a real breakup. This is when a word // is to long to be broken. Well, I don t care this // hack ;-) - if (row->lastPos() == row->par()->size() - 1) - removeRow(row->next()); + if (lastPos(*this, row) == row->par()->size() - 1) + removeRow(boost::next(row)); postPaint(y); breakAgainOneRow(row); // will the cursor be in another row now? - if (row->next() && row->next()->par() == row->par() && - row->lastPos() <= cursor.pos()) { - row = row->next(); + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par() && + lastPos(*this, row) <= cursor.pos()) { + ++row; breakAgainOneRow(row); } setCursor(cursor.par(), cursor.pos(), false, cursor.boundary()); - if (row->next() && row->next()->par() == row->par()) - need_break_row = row->next(); + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par()) + need_break_row = boost::next(row); else need_break_row = rows().end(); } else { // set the dimensions of the row - row->fill(fill(*row, workWidth())); + row->fill(fill(row, workWidth())); int const tmpheight = row->height(); setHeightOfRow(row); if (tmpheight == row->height()) { @@ -2753,7 +2632,7 @@ void LyXText::backspace() // current_font = rawtmpfont; // real_current_font = realtmpfont; - if (isBoundary(bv()->buffer(), cursor.par(), cursor.pos()) + if (isBoundary(bv()->buffer(), *cursor.par(), cursor.pos()) != cursor.boundary()) setCursor(cursor.par(), cursor.pos(), false, !cursor.boundary()); @@ -2776,19 +2655,55 @@ void LyXText::backspace() } +RowList::iterator LyXText::cursorRow() const +{ + return getRow(cursor.par(), cursor.pos()); +} + + +RowList::iterator LyXText::getRow(LyXCursor const & cur) const +{ + return getRow(cur.par(), cur.pos()); +} + + +RowList::iterator +LyXText::getRow(ParagraphList::iterator pit, pos_type pos) const +{ + if (rows().empty()) + return rowlist_.end(); + + // find the first row of the specified paragraph + RowList::iterator rit = rowlist_.begin(); + RowList::iterator end = rowlist_.end(); + while (boost::next(rit) != end && rit->par() != pit) { + ++rit; + } + + // now find the wanted row + while (rit->pos() < pos + && boost::next(rit) != end + && boost::next(rit)->par() == pit + && boost::next(rit)->pos() <= pos) { + ++rit; + } + + return rit; +} + // returns pointer to a specified row RowList::iterator -LyXText::getRow(Paragraph * par, pos_type pos, int & y) const +LyXText::getRow(ParagraphList::iterator pit, pos_type pos, int & y) const { y = 0; if (rows().empty()) - return rows().end(); + return rowlist_.end(); // find the first row of the specified paragraph - RowList::iterator rit = rows().begin(); - RowList::iterator end = rows().end(); - while (boost::next(rit) != end && rit->par() != par) { + RowList::iterator rit = rowlist_.begin(); + RowList::iterator end = rowlist_.end(); + while (boost::next(rit) != end && rit->par() != pit) { y += rit->height(); ++rit; } @@ -2796,7 +2711,7 @@ LyXText::getRow(Paragraph * par, pos_type pos, int & y) const // now find the wanted row while (rit->pos() < pos && boost::next(rit) != end - && boost::next(rit)->par() == par + && boost::next(rit)->par() == pit && boost::next(rit)->pos() <= pos) { y += rit->height(); ++rit; @@ -2808,20 +2723,42 @@ LyXText::getRow(Paragraph * par, pos_type pos, int & y) const RowList::iterator LyXText::getRowNearY(int & y) const { - // If possible we should optimize this method. (Lgb) - int tmpy = 0; - RowList::iterator rit = rows().begin(); - RowList::iterator end = rows().end(); + RowList::iterator rit = anchor_row_; + RowList::iterator const beg = rows().begin(); + RowList::iterator const end = rows().end(); - while (rit != end && boost::next(rit) != end && tmpy + rit->height() <= y) { - tmpy += rit->height(); - ++rit; + if (rows().empty()) { + y = 0; + return end; } + if (rit == end) + rit = beg; - y = tmpy; // return the real y + int tmpy = rit->y(); + + if (tmpy <= y) { + while (rit != end && tmpy <= y) { + tmpy += rit->height(); + ++rit; + } + if (rit != beg) { + --rit; + tmpy -= rit->height(); + } + } else { + while (rit != beg && tmpy > y) { + --rit; + tmpy -= rit->height(); + } + } + if (tmpy < 0 || rit == end) { + tmpy = 0; + rit = beg; + } - //lyxerr << "returned y = " << y << endl; + // return the rel y + y = tmpy; return rit; }