X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext.C;h=8e68a70a32f797702cf157a8266ab2fa36d220dd;hb=fe390e9da1538e20eabbc98977d845295f8e563d;hp=4515e9ff2c483bd7f54c0f2353b3ba3dde9a55ac;hpb=ce3b1fa997fd9451d627d0eae03f8a8336a1c696;p=lyx.git diff --git a/src/text.C b/src/text.C index 4515e9ff2c..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; @@ -58,50 +66,100 @@ extern int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN; extern int bibitemMaxWidth(BufferView *, LyXFont const &); +BufferView * LyXText::bv() +{ + Assert(bv_owner != 0); + return bv_owner; +} + + +BufferView * LyXText::bv() const +{ + Assert(bv_owner != 0); + return bv_owner; +} + + +void LyXText::updateRowPositions() +{ + RowList::iterator rit = rows().begin(); + RowList::iterator rend = rows().end(); + for (int y = 0; rit != rend ; ++rit) { + rit->y(y); + y += rit->height(); + } +} + + int LyXText::top_y() const { - if (!top_row_) + if (anchor_row_ == rowlist_.end()) return 0; - - int y = 0; - for (Row * row = firstrow; row && row != top_row_; row = row->next()) { - y += row->height(); - } - return y + top_row_offset_; + + return anchor_row_->y() + anchor_row_offset_; } void LyXText::top_y(int newy) { - if (!firstrow) + 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; - top_row_ = getRowNearY(y); - top_row_offset_ = newy - y; - lyxerr[Debug::GUI] << "changing reference to row: " << top_row_ - << " offset: " << top_row_offset_ << endl; + RowList::iterator rit = getRowNearY(y); + + if (rit == anchor_row_ && anchor_row_offset_ == newy - y) { + lyxerr[Debug::GUI] << "top_y to same value, skipping update" << endl; + return; + } + + anchor_row_ = rit; + anchor_row_offset_ = newy - y; + lyxerr[Debug::GUI] << "changing reference to row: " << &*anchor_row_ + << " offset: " << anchor_row_offset_ << endl; + postPaint(0); } -int LyXText::workWidth(BufferView & bview) const +void LyXText::anchor_row(RowList::iterator rit) +{ + int old_y = top_y(); + anchor_row_offset_ = 0; + 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; +} + + +int LyXText::workWidth() const { if (inset_owner) { // FIXME: pass (const ?) ref - return inset_owner->textWidth(&bview); + return inset_owner->textWidth(bv()); } - return bview.workWidth(); + return bv()->workWidth(); } -int LyXText::workWidth(BufferView & bview, 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(); @@ -112,41 +170,44 @@ int LyXText::workWidth(BufferView & bview, Inset * inset) const Row dummyrow; dummyrow.par(par); dummyrow.pos(pos); - return workWidth(bview) - leftMargin(&bview, &dummyrow); + return workWidth() - leftMargin(dummyrow); } else { int dummy_y; - Row * row = getRow(par, pos, dummy_y); - Row * frow = row; - while (frow->previous() && frow->par() == frow->previous()->par()) - frow = frow->previous(); + RowList::iterator row = getRow(par, pos, dummy_y); + RowList::iterator frow = row; + RowList::iterator beg = rowlist_.begin(); + + while (frow != beg && frow->par() == boost::prior(frow)->par()) + --frow; // 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 = frow->next(); + ++frow; } if (maxw) return maxw; } - return workWidth(bview); + return workWidth(); } -int LyXText::getRealCursorX(BufferView * bview) const +int LyXText::getRealCursorX() const { int x = cursor.x(); - if (the_locking_inset && (the_locking_inset->getLyXText(bview)!=this)) - x = the_locking_inset->getLyXText(bview)->getRealCursorX(bview); + if (the_locking_inset && (the_locking_inset->getLyXText(bv())!= this)) + x = the_locking_inset->getLyXText(bv())->getRealCursorX(); return x; } -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)) @@ -154,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) && @@ -203,18 +268,23 @@ unsigned char LyXText::transformChar(unsigned char c, Paragraph * par, // // Lgb -int LyXText::singleWidth(BufferView * bview, Paragraph * par, - pos_type pos) const +int LyXText::singleWidth(ParagraphList::iterator pit, pos_type pos) const { - char const c = par->getChar(pos); - return singleWidth(bview, par, pos, c); + if (pos >= pit->size()) + return 0; + + char const c = pit->getChar(pos); + return singleWidth(pit, pos, c); } -int LyXText::singleWidth(BufferView * bview, Paragraph * par, +int LyXText::singleWidth(ParagraphList::iterator pit, pos_type pos, char c) const { - LyXFont const font = getFont(bview->buffer(), par, pos); + if (pos >= pit->size()) + return 0; + + LyXFont const font = getFont(bv()->buffer(), pit, pos); // The most common case is handled first (Asger) if (IsPrintable(c)) { @@ -225,7 +295,7 @@ int LyXText::singleWidth(BufferView * bview, 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; @@ -235,32 +305,66 @@ int LyXText::singleWidth(BufferView * bview, 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 return 3; } #if 1 +#warning inset->update FIXME // 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(bview, font); + tmpinset->update(bv()); #endif - return tmpinset->width(bview, font); + return tmpinset->width(bv(), font); } return 0; } if (IsSeparatorChar(c)) c = ' '; - else if (IsNewlineChar(c)) - c = 'n'; return font_metrics::width(c, font); } -void LyXText::computeBidiTables(Buffer const * buf, Row * row) const +lyx::pos_type LyXText::log2vis(lyx::pos_type pos) const +{ + if (bidi_start == -1) + return pos; + else + return log2vis_list[pos - bidi_start]; +} + + +lyx::pos_type LyXText::vis2log(lyx::pos_type pos) const +{ + if (bidi_start == -1) + return pos; + else + return vis2log_list[pos - bidi_start]; +} + + +lyx::pos_type LyXText::bidi_level(lyx::pos_type pos) const +{ + if (bidi_start == -1) + return 0; + else + return bidi_levels[pos - bidi_start]; +} + + +bool LyXText::bidi_InRange(lyx::pos_type pos) const +{ + return bidi_start == -1 || + (bidi_start <= pos && pos <= bidi_end); +} + + +void LyXText::computeBidiTables(Buffer const * buf, + RowList::iterator row) const { bidi_same_direction = true; if (!lyxrc.rtl_support) { @@ -268,7 +372,9 @@ void LyXText::computeBidiTables(Buffer const * buf, Row * row) const 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; @@ -276,7 +382,7 @@ void LyXText::computeBidiTables(Buffer const * buf, Row * row) const } bidi_start = row->pos(); - bidi_end = row->lastPrintablePos(); + bidi_end = lastPrintablePos(*this, row); if (bidi_start > bidi_end) { bidi_start = -1; @@ -298,25 +404,25 @@ void LyXText::computeBidiTables(Buffer const * buf, Row * row) const 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; } @@ -387,7 +493,7 @@ void LyXText::computeBidiTables(Buffer const * buf, Row * row) const // 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) @@ -402,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) @@ -416,22 +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(BufferView * bview, Row const * row) const +int LyXText::leftMargin(Row const & row) const { Inset * ins; - if ((row->par()->getChar(row->pos()) == Paragraph::META_INSET) && - (ins=row->par()->getInset(row->pos())) && - (ins->needFullRow() || ins->display())) - return LEFT_MARGIN; + + 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 = - bview->buffer()->params.getLyXTextClass(); - LyXLayout_ptr const & layout = row->par()->layout(); + bv()->buffer()->params.getLyXTextClass(); + LyXLayout_ptr const & layout = row.par()->layout(); string parindent = layout->parindent; @@ -442,39 +550,37 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) 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 (!row->par()->getDepth()) { - if (row->par()->layout() == tclass.defaultLayout()) { + if (!row.par()->getDepth()) { + if (row.par()->layout() == tclass.defaultLayout()) { // find the previous same level paragraph - if (row->par()->previous()) { - Paragraph * newpar = row->par() - ->depthHook(row->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 = row->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(bview, &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); + x = leftMargin(dummyrow); } - if (newpar && row->par()->layout() == tclass.defaultLayout()) { + if (newpar != ownerParagraphs().end() && + row.par()->layout() == tclass.defaultLayout()) { if (newpar->params().noindent()) parindent.erase(); else { @@ -484,17 +590,17 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const } } - LyXFont const labelfont = getLabelFont(bview->buffer(), row->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 (!row->par()->getLabelstring().empty()) { + if (!row.par()->getLabelstring().empty()) { x += font_metrics::signedWidth(layout->labelindent, labelfont); - x += font_metrics::width(row->par()->getLabelstring(), + x += font_metrics::width(row.par()->getLabelstring(), labelfont); x += font_metrics::width(layout->labelsep, labelfont); } @@ -502,9 +608,9 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) 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 (!row->par()->empty() && row->pos() >= row->par()->beginningOfBody()) { - if (!row->par()->getLabelWidthString().empty()) { - x += font_metrics::width(row->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); } @@ -512,23 +618,23 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const break; case MARGIN_STATIC: x += font_metrics::signedWidth(layout->leftmargin, tclass.defaultfont()) * 4 - / (row->par()->getDepth() + 4); + / (row.par()->getDepth() + 4); break; case MARGIN_FIRST_DYNAMIC: if (layout->labeltype == LABEL_MANUAL) { - if (row->pos() >= row->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 (row->pos() + } else if (row.pos() // Special case to fix problems with // theorems (JMarc) || (layout->labeltype == LABEL_STATIC && layout->latextype == LATEX_ENVIRONMENT - && ! row->par()->isFirstInSequence())) { + && !isFirstInSequence(row.par(), ownerParagraphs()))) { x += font_metrics::signedWidth(layout->leftmargin, labelfont); } else if (layout->labeltype != LABEL_TOP_ENVIRONMENT @@ -538,7 +644,7 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const x += font_metrics::signedWidth(layout->labelindent, labelfont); x += font_metrics::width(layout->labelsep, labelfont); - x += font_metrics::width(row->par()->getLabelstring(), + x += font_metrics::width(row.par()->getLabelstring(), labelfont); } break; @@ -550,16 +656,17 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const // are *NOT* allowed in the LaTeX realisation of this layout. // find the first row of this paragraph - Row const * tmprow = row; - while (tmprow->previous() - && tmprow->previous()->par() == row->par()) - tmprow = tmprow->previous(); + RowList::iterator tmprit = rowlist_.begin(); + while (tmprit != rowlist_.end() + && tmprit->par() != row.par()) + ++tmprit; - int minfill = tmprow->fill(); - while (tmprow->next() && tmprow->next()->par() == row->par()) { - tmprow = tmprow->next(); - if (tmprow->fill() < minfill) - minfill = tmprow->fill(); + int minfill = tmprit->fill(); + while (boost::next(tmprit) != rowlist_.end() && + boost::next(tmprit)->par() == row.par()) { + ++tmprit; + if (tmprit->fill() < minfill) + minfill = tmprit->fill(); } x += font_metrics::signedWidth(layout->leftmargin, @@ -569,44 +676,44 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const break; } - if ((workWidth(*bview) > 0) && - !row->par()->params().leftIndent().zero()) + if ((workWidth() > 0) && + !row.par()->params().leftIndent().zero()) { - LyXLength const len = row->par()->params().leftIndent(); + LyXLength const len = row.par()->params().leftIndent(); int const tw = inset_owner ? - inset_owner->latexTextWidth(bview) : workWidth(*bview); + inset_owner->latexTextWidth(bv()) : workWidth(); x += len.inPixels(tw); } - LyXAlignment align; // wrong type + LyXAlignment align; - if (row->par()->params().align() == LYX_ALIGN_LAYOUT) + if (row.par()->params().align() == LYX_ALIGN_LAYOUT) align = layout->align; else - align = row->par()->params().align(); + align = row.par()->params().align(); // set the correct parindent - if (row->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 - && ! row->par()->isFirstInSequence())) + && !isFirstInSequence(row.par(), ownerParagraphs()))) && align == LYX_ALIGN_BLOCK - && !row->par()->params().noindent() + && !row.par()->params().noindent() // in tabulars and ert paragraphs are never indented! - && (!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() || - bview->buffer()->params.paragraph_separation == + && (!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, tclass.defaultfont()); } else if (layout->labeltype == LABEL_BIBLIO) { // ale970405 Right width for bibitems - x += bibitemMaxWidth(bview, tclass.defaultfont()); + x += bibitemMaxWidth(bv(), tclass.defaultfont()); } } @@ -617,10 +724,12 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const int LyXText::rightMargin(Buffer const & buf, Row const & row) const { Inset * ins; - if ((row.par()->getChar(row.pos()) == Paragraph::META_INSET) && - (ins=row.par()->getInset(row.pos())) && - (ins->needFullRow() || ins->display())) - return PAPER_MARGIN; + + 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 PAPER_MARGIN; LyXTextClass const & tclass = buf.params.getLyXTextClass(); LyXLayout_ptr const & layout = row.par()->layout(); @@ -629,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); @@ -667,13 +745,13 @@ int LyXText::rightMargin(Buffer const & buf, Row const & row) const } -int LyXText::labelEnd(BufferView & bview, Row const & row) const +int LyXText::labelEnd(Row const & row) const { if (row.par()->layout()->margintype == MARGIN_MANUAL) { Row tmprow = row; tmprow.pos(row.par()->size()); // return the beginning of the body - return leftMargin(&bview, &tmprow); + return leftMargin(tmprow); } // LabelEnd is only needed if the layout @@ -685,100 +763,92 @@ int LyXText::labelEnd(BufferView & bview, 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; - } else if (par->isInset(i) && par->getInset(i)->display()) { - // FIXME: what are we doing modifying stuff here ! - par->getInset(i)->display(false); - } - ++i; } - return par->size(); + return par.size(); } }; -pos_type -LyXText::rowBreakPoint(BufferView & bv, 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(bv) - rightMargin(*bv.buffer(), row); + int width = workWidth() - rightMargin(*bv()->buffer(), row); // 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; - pos_type i = pos; + + if (pos == last) + return last; // Now we iterate through until we reach the right margin // or the end of the par, then choose the possible break // nearest that. - int const left = leftMargin(&bv, &row); + int const left = leftMargin(row); int x = left; // pixel width since last breakpoint int chunkwidth = 0; + bool fullrow = false; - for (i = pos; i < last; ++i) { - - char const c = par->getChar(i); - - if (IsNewlineChar(c)) { + pos_type i = pos; + for (; i < last; ++i) { + if (pit->isNewline(i)) { point = i; break; } - int thiswidth = singleWidth(&bv, par, i, c); + char const c = pit->getChar(i); + + 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(&bv, par, i - 1); - int left_margin = labelEnd(bv, row); - if (thiswidth < left_margin) - thiswidth = left_margin; + 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 + 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 display = (in && (in->display() || in->needFullRow())); - - // check whether a Display() inset is valid here. - // If not, change it to non-display. FIXME: - // we should not be modifying things at this - // point ! - if (in && in->display() && (layout->isCommand() || - (layout->labeltype == LABEL_MANUAL && i < body_pos))) - in->display(false); + 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 if (x >= width) { // if no break before or we are at an inset // that will take up a row, break here - if (point == last || display || chunkwidth >= (width - left)) { + if (point == last || fullrow || chunkwidth >= (width - left)) { if (pos < i) point = i - 1; else @@ -789,21 +859,21 @@ LyXText::rowBreakPoint(BufferView & bv, 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; } continue; } - if (!display) + if (!fullrow) continue; - + // full row insets start at a new row 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 @@ -812,7 +882,8 @@ LyXText::rowBreakPoint(BufferView & bv, Row const & row) const } else { point = i - 1; } - break; + + return point; } if (point == last && x >= width) { @@ -824,8 +895,10 @@ LyXText::rowBreakPoint(BufferView & bv, 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; @@ -833,82 +906,98 @@ LyXText::rowBreakPoint(BufferView & bv, Row const & row) const // returns the minimum space a row needs on the screen in pixel -int LyXText::fill(BufferView & bview, 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(&bview, &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(&bview, &row); - - Paragraph * par = row.par(); - LyXLayout_ptr const & layout = par->layout(); + w = leftMargin(*row); - 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(bview.buffer(), par)); - if (par->isLineSeparator(i - 1)) - w -= singleWidth(&bview, par, i - 1); - int left_margin = labelEnd(bview, 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(&bview, par, i); + w += singleWidth(pit, i); ++i; } if (body_pos > 0 && body_pos > last) { - w += font_metrics::width(layout->labelsep, getLabelFont(bview.buffer(), par)); - if (last >= 0 && par->isLineSeparator(last)) - w -= singleWidth(&bview, par, last); - int const left_margin = labelEnd(bview, 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(*bview.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; } // returns the minimum space a manual label needs on the screen in pixel -int LyXText::labelFill(BufferView & bview, Row const & row) const +int LyXText::labelFill(Row const & row) const { - pos_type last = row.par()->beginningOfBody(); + ParagraphList::iterator pit = row.par(); + + pos_type last = pit->beginningOfBody(); - lyx::Assert(last > 0); + 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(&bview, 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(bview.buffer(), row.par()); + LyXFont const labfont = getLabelFont(bv()->buffer(), pit); int const labwidth = font_metrics::width(labwidstr, labfont); fill = max(labwidth - w, 0); } @@ -925,11 +1014,12 @@ LColor::color LyXText::backgroundColor() const return LColor::background; } -void LyXText::setHeightOfRow(BufferView * bview, Row * row) 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; @@ -943,27 +1033,26 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const // Correction: only the fontsize count. The other properties // are taken from the layoutfont. Nicer on the screen :) - Paragraph * par = row->par(); - Paragraph * firstpar = row->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(bview->buffer(), par, row->pos()); + LyXFont font = getFont(bv()->buffer(), pit, rit->pos()); LyXFont::FONT_SIZE const tmpsize = font.size(); - font = getLayoutFont(bview->buffer(), par); + font = getLayoutFont(bv()->buffer(), pit); LyXFont::FONT_SIZE const size = font.size(); font.setSize(tmpsize); - LyXFont labelfont = getLabelFont(bview->buffer(), par); + LyXFont labelfont = getLabelFont(bv()->buffer(), pit); float spacing_val = 1.0; - if (!row->par()->params().spacing().isDefault()) { - spacing_val = row->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { - spacing_val = bview->buffer()->params.spacing.getValue(); + spacing_val = bv()->buffer()->params.spacing.getValue(); } //lyxerr << "spacing_val = " << spacing_val << endl; @@ -974,27 +1063,30 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const layout->spacing.getValue() * spacing_val); - pos_type const pos_end = row->lastPos(); + pos_type const pos_end = lastPos(*this, rit); int labeladdon = 0; int maxwidth = 0; - // Check if any insets are larger - for (pos_type pos = row->pos(); pos <= pos_end; ++pos) { - if (row->par()->isInset(pos)) { - tmpfont = getFont(bview->buffer(), row->par(), pos); - tmpinset = row->par()->getInset(pos); - if (tmpinset) { + if (!pit->empty()) { + // Check if any insets are larger + for (pos_type pos = rit->pos(); pos <= pos_end; ++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 - tmpinset->update(bview, tmpfont); +#warning inset->update FIXME + tmpinset->update(bv()); #endif - asc = tmpinset->ascent(bview, tmpfont); - desc = tmpinset->descent(bview, tmpfont); - maxwidth += tmpinset->width(bview, tmpfont); - maxasc = max(maxasc, asc); - maxdesc = max(maxdesc, desc); + maxwidth += tmpinset->width(bv(), tmpfont); + maxasc = max(maxasc, + tmpinset->ascent(bv(), tmpfont)); + maxdesc = max(maxdesc, + tmpinset->descent(bv(), tmpfont)); + } + } else { + maxwidth += singleWidth(pit, pos); } - } else { - maxwidth += singleWidth(bview, row->par(), pos); } } @@ -1002,72 +1094,70 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const // This is not completely correct, but we can live with the small, // cosmetic error for now. LyXFont::FONT_SIZE maxsize = - row->par()->highestFontInRange(row->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: ++maxasc; ++maxdesc; - row->ascent_of_text(maxasc); + rit->ascent_of_text(maxasc); // is it a top line? - if (!row->pos() && (row->par() == firstpar)) { + if (!rit->pos()) { // some parksips VERY EASY IMPLEMENTATION - if (bview->buffer()->params.paragraph_separation == + if (bv()->buffer()->params.paragraph_separation == BufferParams::PARSEP_SKIP) { if (layout->isParagraph() - && firstpar->getDepth() == 0 - && firstpar->previous()) + && pit->getDepth() == 0 + && pit != ownerParagraphs().begin()) { - maxasc += bview->buffer()->params.getDefSkip().inPixels(*bview); - } else if (firstpar->previous() && - firstpar->previous()->layout()->isParagraph() && - firstpar->previous()->getDepth() == 0) + maxasc += bv()->buffer()->params.getDefSkip().inPixels(*bv()); + } 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 += bview->buffer()->params.getDefSkip().inPixels(*bview); + maxasc += bv()->buffer()->params.getDefSkip().inPixels(*bv()); } } // the top margin - if (!row->par()->previous() && isTopLevel()) + if (pit == ownerParagraphs().begin() && !isInInset()) maxasc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxasc += getLengthMarkerHeight(*bview, 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(bview->buffer(), - firstpar, 0)); + maxasc += 2 * font_metrics::ascent('x', getFont(bv()->buffer(), + pit, 0)); // and now the pagebreaks - if (firstpar->params().pagebreakTop()) + if (pit->params().pagebreakTop()) + maxasc += 3 * defaultRowHeight(); + + if (pit->params().startOfAppendix()) maxasc += 3 * defaultRowHeight(); // This is special code for the chapter, since the label of this // layout is printed in an extra row if (layout->labeltype == LABEL_COUNTER_CHAPTER - && bview->buffer()->params.secnumdepth >= 0) + && bv()->buffer()->params.secnumdepth >= 0) { float spacing_val = 1.0; - if (!row->par()->params().spacing().isDefault()) { - spacing_val = row->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { - spacing_val = bview->buffer()->params.spacing.getValue(); + spacing_val = bv()->buffer()->params.spacing.getValue(); } labeladdon = int(font_metrics::maxDescent(labelfont) * @@ -1082,14 +1172,14 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const if ((layout->labeltype == LABEL_TOP_ENVIRONMENT || layout->labeltype == LABEL_BIBLIO || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) - && row->par()->isFirstInSequence() - && !row->par()->getLabelstring().empty()) + && isFirstInSequence(pit, ownerParagraphs()) + && !pit->getLabelstring().empty()) { float spacing_val = 1.0; - if (!row->par()->params().spacing().isDefault()) { - spacing_val = row->par()->params().spacing().getValue(); + if (!pit->params().spacing().isDefault()) { + spacing_val = pit->params().spacing().getValue(); } else { - spacing_val = bview->buffer()->params.spacing.getValue(); + spacing_val = bv()->buffer()->params.spacing.getValue(); } labeladdon = int( @@ -1103,44 +1193,41 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const + 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 = row->par()->previous(); - if (prev) - prev = row->par()->depthHook(row->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 (row->previous()) { + } else if (rit != rows().begin()) { tmptop = layout->topsep; - if (row->previous()->par()->getDepth() >= row->par()->getDepth()) - tmptop -= row->previous()->par()->layout()->bottomsep; + if (boost::prior(pit)->getDepth() >= pit->getDepth()) + tmptop -= boost::prior(rit)->par()->layout()->bottomsep; if (tmptop > 0) layoutasc = (tmptop * defaultRowHeight()); - } else if (row->par()->params().lineTop()) { + } else if (pit->params().lineTop()) { tmptop = layout->topsep; if (tmptop > 0) layoutasc = (tmptop * defaultRowHeight()); } - prev = row->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()); } } @@ -1148,89 +1235,91 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const } // is it a bottom line? - if (row->par() == par - && (!row->next() || row->next()->par() != row->par())) { + RowList::iterator next_rit = boost::next(rit); + if (next_rit == rows().end() || + next_rit->par() != pit) { // the bottom margin - if (!par->next() && isTopLevel()) + ParagraphList::iterator nextpit = boost::next(pit); + if (nextpit == ownerParagraphs().end() && + !isInInset()) maxdesc += PAPER_MARGIN; // add the vertical spaces, that the user added - maxdesc += getLengthMarkerHeight(*bview, 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(bview->buffer(), - par, - max(pos_type(0), par->size() - 1))); + getFont(bv()->buffer(), + 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() - && row->par()->next()) { - Paragraph * nextpar = row->par()->next(); - Paragraph * comparepar = row->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 -= row->height(); + height -= rit->height(); - row->height(maxasc + maxdesc + labeladdon); - row->baseline(maxasc + labeladdon); + rit->height(maxasc + maxdesc + labeladdon); + rit->baseline(maxasc + labeladdon); - height += row->height(); + height += rit->height(); - row->top_of_text(row->baseline() - font_metrics::maxAscent(font)); + rit->top_of_text(rit->baseline() - font_metrics::maxAscent(font)); float x = 0; if (layout->margintype != MARGIN_RIGHT_ADDRESS_BOX) { float dummy; // this IS needed - row->width(maxwidth); - prepareToPrint(bview, row, x, dummy, dummy, dummy, false); + rit->width(maxwidth); + prepareToPrint(rit, x, dummy, dummy, dummy, false); } - row->width(int(maxwidth + x)); + rit->width(int(maxwidth + x)); if (inset_owner) { - Row * r = firstrow; - width = max(0, workWidth(*bview)); - while (r) { - if (r->width() > width) - width = r->width(); - r = r->next(); + width = max(0, workWidth()); + RowList::iterator it = rows().begin(); + RowList::iterator end = rows().end(); + for (; it != end; ++it) { + if (it->width() > width) + width = it->width(); } } } @@ -1238,21 +1327,22 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row) const // Appends the implicit specified paragraph before the specified row, // start at the implicit given position -void LyXText::appendParagraph(BufferView * bview, Row * row) const +void LyXText::appendParagraph(RowList::iterator rowit) { - pos_type const last = row->par()->size(); + Assert(rowit != rowlist_.end()); + + pos_type const last = rowit->par()->size(); bool done = false; do { - pos_type z = rowBreakPoint(*bview, *row); + pos_type z = rowBreakPoint(*rowit); - Row * tmprow = row; + RowList::iterator tmprow = rowit; if (z < last) { ++z; - insertRow(row, row->par(), z); - row = row->next(); - row->height(0); + Row newrow(rowit->par(), z); + rowit = rowlist_.insert(boost::next(rowit), newrow); } else { done = true; } @@ -1260,123 +1350,111 @@ void LyXText::appendParagraph(BufferView * bview, Row * row) const // Set the dimensions of the row // fixed fill setting now by calling inset->update() in // SingleWidth when needed! - tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); - setHeightOfRow(bview, tmprow); + tmprow->fill(fill(tmprow, workWidth())); + setHeightOfRow(tmprow); } while (!done); } -// Do we even need this at all ? Code that uses RowPainter *already* -// sets need_break_row when it sees a CHANGED_IN_DRAW, though not -// quite like this -void LyXText::markChangeInDraw(BufferView * bv, Row * row, Row * prev) +void LyXText::breakAgain(RowList::iterator rit) { - if (prev && prev->par() == row->par()) { - breakAgainOneRow(bv, prev); - if (prev->next() != row) { - // breakAgainOneRow() has removed row_ - need_break_row = prev; - } else { - need_break_row = row; - } - } else if (!prev) { - need_break_row = firstrow; - } else { - need_break_row = prev->next(); - } - setCursor(bv, cursor.par(), cursor.pos()); - /* FIXME */ -} - + Assert(rit != rows().end()); -void LyXText::breakAgain(BufferView * bview, Row * row) const -{ bool not_ready = true; do { - pos_type z = rowBreakPoint(*bview, *row); - Row * tmprow = row; + pos_type z = rowBreakPoint(*rit); + RowList::iterator tmprit = rit; + RowList::iterator end = rows().end(); + + if (z < rit->par()->size()) { + RowList::iterator next_rit = boost::next(rit); - if (z < row->par()->size()) { - if (!row->next() || (row->next() && row->next()->par() != row->par())) { + if (next_rit == end || + (next_rit != end && + next_rit->par() != rit->par())) { // insert a new row ++z; - insertRow(row, row->par(), z); - row = row->next(); - row->height(0); + Row newrow(rit->par(), z); + rit = rowlist_.insert(next_rit, newrow); } else { - row = row->next(); + ++rit; ++z; - if (row->pos() == z) - not_ready = false; // the rest will not change + if (rit->pos() == z) + not_ready = false; // the rest will not change else { - row->pos(z); + rit->pos(z); } } } else { // if there are some rows too much, delete them // only if you broke the whole paragraph! - Row * tmprow2 = row; - while (tmprow2->next() && tmprow2->next()->par() == row->par()) { - tmprow2 = tmprow2->next(); + RowList::iterator tmprit2 = rit; + while (boost::next(tmprit2) != end + && boost::next(tmprit2)->par() == rit->par()) { + ++tmprit2; } - while (tmprow2 != row) { - tmprow2 = tmprow2->previous(); - removeRow(tmprow2->next()); + while (tmprit2 != rit) { + --tmprit2; + removeRow(boost::next(tmprit2)); } not_ready = false; } // set the dimensions of the row - tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); - setHeightOfRow(bview, tmprow); + tmprit->fill(fill(tmprit, workWidth())); + setHeightOfRow(tmprit); } while (not_ready); } // this is just a little changed version of break again -void LyXText::breakAgainOneRow(BufferView * bview, Row * row) +void LyXText::breakAgainOneRow(RowList::iterator rit) { - pos_type z = rowBreakPoint(*bview, *row); - Row * tmprow = row; + Assert(rit != rows().end()); - if (z < row->par()->size()) { - if (!row->next() - || (row->next() && row->next()->par() != row->par())) { + pos_type z = rowBreakPoint(*rit); + RowList::iterator tmprit = rit; + RowList::iterator end = rows().end(); + + if (z < rit->par()->size()) { + RowList::iterator next_rit = boost::next(rit); + + if (next_rit == end || + (next_rit != end && + next_rit->par() != rit->par())) { // insert a new row ++z; - insertRow(row, row->par(), z); - row = row->next(); - row->height(0); + Row newrow(rit->par(), z); + rit = rowlist_.insert(next_rit, newrow); } else { - row = row->next(); + ++rit; ++z; - if (row->pos() != z) - row->pos(z); + if (rit->pos() != z) + rit->pos(z); } } else { // if there are some rows too much, delete them // only if you broke the whole paragraph! - Row * tmprow2 = row; - while (tmprow2->next() - && tmprow2->next()->par() == row->par()) { - tmprow2 = tmprow2->next(); + RowList::iterator tmprit2 = rit; + while (boost::next(tmprit2) != end + && boost::next(tmprit2)->par() == rit->par()) { + ++tmprit2; } - while (tmprow2 != row) { - tmprow2 = tmprow2->previous(); - removeRow(tmprow2->next()); + while (tmprit2 != rit) { + --tmprit2; + removeRow(boost::next(tmprit2)); } } // set the dimensions of the row - tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); - setHeightOfRow(bview, tmprow); + tmprit->fill(fill(tmprit, workWidth())); + setHeightOfRow(tmprit); } -void LyXText::breakParagraph(BufferView * bview, - ParagraphList & paragraphs, char keep_layout) +void LyXText::breakParagraph(ParagraphList & paragraphs, char keep_layout) { // allow only if at start or end, or all previous is new text if (cursor.pos() && cursor.pos() != cursor.par()->size() @@ -1384,17 +1462,16 @@ void LyXText::breakParagraph(BufferView * bview, return; LyXTextClass const & tclass = - bview->buffer()->params.getLyXTextClass(); + bv()->buffer()->params.getLyXTextClass(); 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(bview, Undo::FINISH, cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::FINISH, cursor.par()); // Always break behind a space // @@ -1414,8 +1491,8 @@ void LyXText::breakParagraph(BufferView * bview, // 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()); - ::breakParagraph(bview->buffer()->params, paragraphs, cursor.par(), cursor.pos(), + bool const isempty = (cursor.par()->allowEmpty() && cursor.par()->empty()); + ::breakParagraph(bv()->buffer()->params, paragraphs, cursor.par(), cursor.pos(), keep_layout); // well this is the caption hack since one caption is really enough @@ -1425,85 +1502,87 @@ void LyXText::breakParagraph(BufferView * bview, 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(bview); + cursorLeft(bv()); } - status(bview, LyXText::NEED_MORE_REFRESH); - refresh_row = cursor.row(); - refresh_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) { - while (refresh_row->previous() && - refresh_row->previous()->par() == refresh_row->par()) - { - refresh_row = refresh_row->previous(); - refresh_y -= refresh_row->height(); + RowList::iterator r = cursorRow(); + RowList::iterator beg = rows().begin(); + + while (r != beg && boost::prior(r)->par() == r->par()) { + --r; + y -= r->height(); } } - removeParagraph(cursor.row()); + + postPaint(y); + + removeParagraph(cursorRow()); // set the dimensions of the cursor row - cursor.row()->fill(fill(*bview, *cursor.row(), workWidth(*bview))); + cursorRow()->fill(fill(cursorRow(), workWidth())); - setHeightOfRow(bview, 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()); - insertParagraph(bview, cursor.par()->next(), cursor.row()); + while (!next_par->empty() && next_par->isNewline(0)) + next_par->erase(0); - updateCounters(bview); + 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(bview, cursor.par()->next(), 0); + setCursor(next_par, 0); else - setCursor(bview, cursor.par(), 0); + setCursor(cursor.par(), 0); - if (cursor.row()->next()) - breakAgain(bview, cursor.row()->next()); + if (boost::next(cursorRow()) != rows().end()) + breakAgain(boost::next(cursorRow())); - need_break_row = 0; + need_break_row = rows().end(); } // Just a macro to make some thing easier. -void LyXText::redoParagraph(BufferView * bview) const +void LyXText::redoParagraph() { clearSelection(); - redoParagraphs(bview, cursor, cursor.par()->next()); - setCursorIntern(bview, cursor.par(), cursor.pos()); + redoParagraphs(cursor, boost::next(cursor.par())); + setCursorIntern(cursor.par(), cursor.pos()); } // insert a character, moves all the following breaks in the // same Paragraph one to the right and make a rebreak -void LyXText::insertChar(BufferView * bview, char c) +void LyXText::insertChar(char c) { - setUndo(bview, 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 = "+-/*"; @@ -1515,17 +1594,17 @@ void LyXText::insertChar(BufferView * bview, char c) !(contains(number_seperators, c) && cursor.pos() >= 1 && cursor.pos() < cursor.par()->size() && - getFont(bview->buffer(), + getFont(bv()->buffer(), cursor.par(), cursor.pos()).number() == LyXFont::ON && - getFont(bview->buffer(), + getFont(bv()->buffer(), cursor.par(), cursor.pos() - 1).number() == LyXFont::ON) ) - number(bview); // Set current_font.number to OFF + number(bv()); // Set current_font.number to OFF } else if (IsDigit(c) && real_current_font.isVisibleRightToLeft()) { - number(bview); // Set current_font.number to ON + number(bv()); // Set current_font.number to ON if (cursor.pos() > 0) { char const c = cursor.par()->getChar(cursor.pos() - 1); @@ -1534,16 +1613,16 @@ void LyXText::insertChar(BufferView * bview, char c) cursor.par()->isSeparator(cursor.pos() - 2) || cursor.par()->isNewline(cursor.pos() - 2)) ) { - setCharFont(bview->buffer(), + setCharFont(bv()->buffer(), cursor.par(), cursor.pos() - 1, current_font); } else if (contains(number_seperators, c) && cursor.pos() >= 2 && - getFont(bview->buffer(), + getFont(bv()->buffer(), cursor.par(), cursor.pos() - 2).number() == LyXFont::ON) { - setCharFont(bview->buffer(), + setCharFont(bv()->buffer(), cursor.par(), cursor.pos() - 1, current_font); @@ -1572,7 +1651,7 @@ void LyXText::insertChar(BufferView * bview, char c) // Get the font that is used to calculate the baselineskip pos_type const lastpos = cursor.par()->size(); LyXFont rawparfont = - cursor.par()->getFontSettings(bview->buffer()->params, + cursor.par()->getFontSettings(bv()->buffer()->params, lastpos - 1); bool jumped_over_space = false; @@ -1586,98 +1665,89 @@ void LyXText::insertChar(BufferView * bview, char c) static bool sent_space_message = false; if (!sent_space_message) { if (cursor.pos() == 0) - bview->owner()->message(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial.")); + bv()->owner()->message(_("You cannot insert a space at the beginning of a paragraph. Please read the Tutorial.")); else - bview->owner()->message(_("You cannot type two spaces this way. Please read the Tutorial.")); + bv()->owner()->message(_("You cannot type two spaces this way. Please read the Tutorial.")); sent_space_message = true; } charInserted(); return; } - } else if (IsNewlineChar(c)) { - if (cursor.pos() <= cursor.par()->beginningOfBody()) { - charInserted(); - return; - } - // No newline at first position of a paragraph or behind labels. - // TeX does not allow that - - if (cursor.pos() < cursor.par()->size() && - cursor.par()->isLineSeparator(cursor.pos())) - // newline always after a blank! - cursorRight(bview); - cursor.row()->fill(-1); // to force a new break } // the display inset stuff - if (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 cursor.par()->insertChar(cursor.pos(), c); } - setCharFont(bview->buffer(), cursor.par(), cursor.pos(), rawtmpfont); + setCharFont(bv()->buffer(), cursor.par(), cursor.pos(), rawtmpfont); 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() < cursor.par()->size()) && - cursor.par()->isInset(cursor.pos()+1)) - || cursor.row()->fill() == -1)) + || ((cursor.pos() + 1 < cursor.par()->size()) && + cursor.par()->isInset(cursor.pos() + 1)) + || cursorRow()->fill() == -1)) { - pos_type z = rowBreakPoint(*bview, *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(*bview, - *row->previous(), - workWidth(*bview))); + boost::prior(row)->fill(fill( + boost::prior(row), + workWidth())); + + setHeightOfRow(boost::prior(row)); - setHeightOfRow(bview, row->previous()); + y -= boost::prior(row)->height(); - y -= row->previous()->height(); - refresh_y = y; - refresh_row = row->previous(); - status(bview, LyXText::NEED_MORE_REFRESH); + postPaint(y); - breakAgainOneRow(bview, row); + breakAgainOneRow(row); current_font = rawtmpfont; real_current_font = realtmpfont; - setCursor(bview, cursor.par(), cursor.pos() + 1, + setCursor(cursor.par(), cursor.pos() + 1, 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 = 0; + need_break_row = rows().end(); // check, wether the last characters font has changed. if (cursor.pos() && cursor.pos() == cursor.par()->size() && rawparfont != rawtmpfont) - redoHeightOfParagraph(bview, cursor); + redoHeightOfParagraph(); charInserted(); return; @@ -1688,60 +1758,70 @@ void LyXText::insertChar(BufferView * bview, 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(*bview, *row, workWidth(*bview))); + row->fill(fill(row, workWidth())); } if (c == Paragraph::META_INSET || row->fill() < 0) { - refresh_y = y; - refresh_row = row; - status(bview, LyXText::NEED_MORE_REFRESH); - breakAgainOneRow(bview, row); + 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(); - breakAgainOneRow(bview, row); + ++row; + } + + breakAgainOneRow(row); } current_font = rawtmpfont; real_current_font = realtmpfont; - setCursor(bview, cursor.par(), cursor.pos() + 1, false, + setCursor(cursor.par(), cursor.pos() + 1, false, cursor.boundary()); - if (isBoundary(bview->buffer(), cursor.par(), cursor.pos()) + if (isBoundary(bv()->buffer(), *cursor.par(), cursor.pos()) != cursor.boundary()) - setCursor(bview, cursor.par(), cursor.pos(), false, + 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 = 0; + need_break_row = rows().end(); } else { - refresh_y = y; - refresh_row = row; - + // FIXME: similar code is duplicated all over - make resetHeightOfRow int const tmpheight = row->height(); - setHeightOfRow(bview, row); - if (tmpheight == row->height()) - status(bview, LyXText::NEED_VERY_LITTLE_REFRESH); - else - status(bview, LyXText::NEED_MORE_REFRESH); + + setHeightOfRow(row); + + if (tmpheight == row->height()) { + postRowPaint(row, y); + } else { + postPaint(y); + } current_font = rawtmpfont; real_current_font = realtmpfont; - setCursor(bview, cursor.par(), cursor.pos() + 1, false, + setCursor(cursor.par(), cursor.pos() + 1, false, cursor.boundary()); } // check, wether the last characters font has changed. if (cursor.pos() && cursor.pos() == cursor.par()->size() && rawparfont != rawtmpfont) { - redoHeightOfParagraph(bview, cursor); + redoHeightOfParagraph(); } else { // now the special right address boxes if (cursor.par()->layout()->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - redoDrawingOfParagraph(bview, cursor); + redoDrawingOfParagraph(cursor); } } @@ -1752,7 +1832,7 @@ void LyXText::insertChar(BufferView * bview, 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; @@ -1763,54 +1843,52 @@ void LyXText::charInserted() } -void LyXText::prepareToPrint(BufferView * bview, - Row * row, float & x, +void LyXText::prepareToPrint(RowList::iterator rit, float & x, float & fill_separator, float & fill_hfill, float & fill_label_hfill, bool bidi) const { - float nlh; - float ns; - - float w = row->fill(); + 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 = - row->par()->isRightToLeftPar(bview->buffer()->params); + pit->isRightToLeftPar(bv()->buffer()->params); if (is_rtl) { - x = (workWidth(*bview) > 0) - ? rightMargin(*bview->buffer(), *row) : 0; + x = (workWidth() > 0) + ? rightMargin(*bv()->buffer(), *rit) : 0; } else - x = (workWidth(*bview) > 0) - ? leftMargin(bview, row) : 0; + x = (workWidth() > 0) + ? leftMargin(*rit) : 0; // is there a manual margin with a manual label - LyXLayout_ptr const & layout = row->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 = row->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 (!row->par()->empty()) + if (!pit->empty()) ++nlh; - - if (nlh && !row->par()->getLabelWidthString().empty()) { - fill_label_hfill = labelFill(*bview, *row) / nlh; + + if (nlh && !pit->getLabelWidthString().empty()) { + fill_label_hfill = labelFill(*rit) / nlh; } } // are there any hfills in the row? - float const nh = row->numberOfHfills(); + float const nh = numberOfHfills(*this, rit); if (nh) { if (w > 0) @@ -1818,25 +1896,26 @@ void LyXText::prepareToPrint(BufferView * bview, // we don't have to look at the alignment if it is ALIGN_LEFT and // if the row is already larger then the permitted width as then // we force the LEFT_ALIGN'edness! - } else if (static_cast(row->width()) < workWidth(*bview)) { + } else if (static_cast(rit->width()) < workWidth()) { // is it block, flushleft or flushright? // set x how you need it int align; - if (row->par()->params().align() == LYX_ALIGN_LAYOUT) { + if (pit->params().align() == LYX_ALIGN_LAYOUT) { align = layout->align; } else { - align = row->par()->params().align(); + align = pit->params().align(); } // center displayed insets - Inset * inset; - if (row->par()->isInset(row->pos()) - && (inset=row->par()->getInset(row->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 = row->par()->inInset(); + inset = pit->inInset(); if (inset && inset->owner() && inset->owner()->lyxCode() == Inset::ERT_CODE) { @@ -1845,19 +1924,24 @@ void LyXText::prepareToPrint(BufferView * bview, switch (align) { case LYX_ALIGN_BLOCK: - ns = row->numberOfSeparators(); - if (ns && row->next() && row->next()->par() == row->par() && - !(row->next()->par()->isNewline(row->next()->pos() - 1)) - && !(row->next()->par()->isInset(row->next()->pos()) - && row->next()->par()->getInset(row->next()->pos()) - && row->next()->par()->getInset(row->next()->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; @@ -1869,16 +1953,17 @@ void LyXText::prepareToPrint(BufferView * bview, if (!bidi) return; - computeBidiTables(bview->buffer(), row); + computeBidiTables(bv()->buffer(), rit); if (is_rtl) { - pos_type body_pos = row->par()->beginningOfBody(); - pos_type last = row->lastPos(); + pos_type body_pos = pit->beginningOfBody(); + pos_type last = lastPos(*this, rit); if (body_pos > 0 && (body_pos - 1 > last || - !row->par()->isLineSeparator(body_pos - 1))) { + !pit->isLineSeparator(body_pos - 1))) { x += font_metrics::width(layout->labelsep, - getLabelFont(bview->buffer(), row->par())); + getLabelFont(bv()->buffer(), + pit)); if (body_pos - 1 <= last) x += fill_label_hfill; } @@ -1893,206 +1978,83 @@ void LyXText::prepareToPrint(BufferView * bview, // realize, that you left an empty paragraph, they will delete it. // They also delete the corresponding row -void LyXText::cursorRightOneWord(BufferView * bview) const +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(bview, tmpcursor.par(), tmpcursor.pos()); -} - - -void LyXText::cursorTab(BufferView * bview) const -{ - 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(bview, tmpcursor.par(), tmpcursor.pos()); + ::cursorRightOneWord(cursor, ownerParagraphs()); + setCursor(cursor.par(), cursor.pos()); } // Skip initial whitespace at end of word and move cursor to *start* // of prior word, not to end of next prior word. -void LyXText::cursorLeftOneWord(BufferView * bview) const +void LyXText::cursorLeftOneWord() { LyXCursor tmpcursor = cursor; - cursorLeftOneWord(tmpcursor); - setCursor(bview, tmpcursor.par(), tmpcursor.pos()); -} - - -void LyXText::cursorLeftOneWord(LyXCursor & cur) const -{ - // 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()->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) const -{ - // 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()->isSeparator(cursor.pos() - 1) - || cursor.par()->isKomma(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)) - 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()->isHfill(to.pos()) - && !to.par()->isInset(to.pos())) - { - to.pos(to.pos() + 1); - } + ::cursorLeftOneWord(tmpcursor, ownerParagraphs()); + setCursor(tmpcursor.par(), tmpcursor.pos()); } -void LyXText::selectWord(BufferView * bview, word_location const loc) +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(bview, from.par(), from.pos()); + setCursor(from.par(), from.pos()); if (to == from) return; selection.cursor = cursor; - setCursor(bview, to.par(), to.pos()); - setSelection(bview); + setCursor(to.par(), to.pos()); + setSelection(); } // Select the word currently under the cursor when no // selection is currently set -bool LyXText::selectWordWhenUnderCursor(BufferView * bview, - word_location const loc) +bool LyXText::selectWordWhenUnderCursor(word_location loc) { if (!selection.set()) { - selectWord(bview, loc); + selectWord(loc); return selection.set(); } return false; } -void LyXText::acceptChange(BufferView * bv) +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(bv, startc, startc.par()->next()); - setCursorIntern(bv, startc.par(), 0); + redoParagraphs(startc, boost::next(startc.par())); + setCursorIntern(startc.par(), 0); } #warning handle multi par selection } -void LyXText::rejectChange(BufferView * bv) +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(bv, startc, startc.par()->next()); - setCursorIntern(bv, startc.par(), 0); + redoParagraphs(startc, boost::next(startc.par())); + setCursorIntern(startc.par(), 0); } #warning handle multi par selection } @@ -2101,10 +2063,10 @@ void LyXText::rejectChange(BufferView * bv) // This function is only used by the spellchecker for NextWord(). // It doesn't handle LYX_ACCENTs and probably never will. WordLangTuple const -LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const +LyXText::selectNextWordToSpellcheck(float & value) { if (the_locking_inset) { - WordLangTuple word = the_locking_inset->selectNextWordToSpellcheck(bview, value); + WordLangTuple word = the_locking_inset->selectNextWordToSpellcheck(bv(), value); if (!word.word().empty()) { value += float(cursor.y()); value /= float(height); @@ -2112,43 +2074,43 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const } // 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); @@ -2158,15 +2120,16 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const if (cursor.pos() < cursor.par()->size() && cursor.par()->isInset(cursor.pos())) { // lock the inset! - cursor.par()->getInset(cursor.pos())->edit(bview); + 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 bview->text->selectNextWordToSpellcheck(bview, value); + return bv()->text->selectNextWordToSpellcheck(value); } // Update the value if we changed paragraphs - if (cursor.par() != tmppar) { - setCursor(bview, cursor.par(), cursor.pos()); + if (cursor.par() != tmppit) { + setCursor(cursor.par(), cursor.pos()); value = float(cursor.y())/float(height); } @@ -2174,7 +2137,7 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const selection.cursor = cursor; string lang_code( - getFont(bview->buffer(), cursor.par(), cursor.pos()) + getFont(bv()->buffer(), cursor.par(), cursor.pos()) .language()->code()); // and find the end of the word (insets like optional hyphens // and ligature break are part of a word) @@ -2197,14 +2160,14 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const // This one is also only for the spellchecker -void LyXText::selectSelectedWord(BufferView * bview) +void LyXText::selectSelectedWord() { if (the_locking_inset) { - the_locking_inset->selectSelectedWord(bview); + the_locking_inset->selectSelectedWord(bv()); return; } // move cursor to the beginning - setCursor(bview, selection.cursor.par(), selection.cursor.pos()); + setCursor(selection.cursor.par(), selection.cursor.pos()); // set the sel cursor selection.cursor = cursor; @@ -2214,81 +2177,78 @@ void LyXText::selectSelectedWord(BufferView * bview) && (cursor.par()->isLetter(cursor.pos()))) cursor.pos(cursor.pos() + 1); - setCursor(bview, cursor.par(), cursor.pos()); + setCursor(cursor.par(), cursor.pos()); // finally set the selection - setSelection(bview); + setSelection(); } // Delete from cursor up to the end of the current or next word. -void LyXText::deleteWordForward(BufferView * bview) +void LyXText::deleteWordForward() { if (cursor.par()->empty()) - cursorRight(bview); + cursorRight(bv()); else { LyXCursor tmpcursor = cursor; - tmpcursor.row(0); // ?? selection.set(true); // to avoid deletion - cursorRightOneWord(bview); - setCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos()); + cursorRightOneWord(); + setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); selection.cursor = cursor; cursor = tmpcursor; - setSelection(bview); + setSelection(); // Great, CutSelection() gets rid of multiple spaces. - cutSelection(bview, true, false); + cutSelection(true, false); } } // Delete from cursor to start of current or prior word. -void LyXText::deleteWordBackward(BufferView * bview) +void LyXText::deleteWordBackward() { if (cursor.par()->empty()) - cursorLeft(bview); + cursorLeft(bv()); else { LyXCursor tmpcursor = cursor; - tmpcursor.row(0); // ?? selection.set(true); // to avoid deletion - cursorLeftOneWord(bview); - setCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos()); + cursorLeftOneWord(); + setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); selection.cursor = cursor; cursor = tmpcursor; - setSelection(bview); - cutSelection(bview, true, false); + setSelection(); + cutSelection(true, false); } } // Kill to end of line. -void LyXText::deleteLineForward(BufferView * bview) +void LyXText::deleteLineForward() { if (cursor.par()->empty()) // Paragraph is empty, so we just go to the right - cursorRight(bview); + cursorRight(bv()); else { 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(bview); - setCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos()); + cursorEnd(); + setCursor(tmpcursor, tmpcursor.par(), tmpcursor.pos()); selection.cursor = cursor; cursor = tmpcursor; - setSelection(bview); + setSelection(); // What is this test for ??? (JMarc) if (!selection.set()) { - deleteWordForward(bview); + deleteWordForward(); } else { - cutSelection(bview, true, false); + cutSelection(true, false); } } } -void LyXText::changeCase(BufferView & bview, LyXText::TextCase action) +void LyXText::changeCase(LyXText::TextCase action) { LyXCursor from; LyXCursor to; @@ -2297,24 +2257,24 @@ void LyXText::changeCase(BufferView & bview, LyXText::TextCase action) from = selection.start; to = selection.end; } else { - getWord(from, to, PARTIAL_WORD); - setCursor(&bview, to.par(), to.pos() + 1); + from = cursor; + ::getWord(from, to, lyx::PARTIAL_WORD, ownerParagraphs()); + setCursor(to.par(), to.pos() + 1); } - lyx::Assert(from <= to); - - setUndo(&bview, 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: @@ -2330,65 +2290,29 @@ void LyXText::changeCase(BufferView & bview, LyXText::TextCase action) } } #warning changes - par->setChar(pos, c); - checkParagraph(&bview, par, pos); + pit->setChar(pos, c); + checkParagraph(pit, pos); ++pos; } - if (to.row() != from.row()) { - refresh_y = from.y() - from.row()->baseline(); - refresh_row = from.row(); - status(&bview, LyXText::NEED_MORE_REFRESH); - } -} - - -void LyXText::transposeChars(BufferView & bview) -{ - Paragraph * tmppar = cursor.par(); - setUndo(&bview, 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(&bview, tmppar, tmppos); + if (getRow(to) != getRow(from)) + postPaint(from.y() - getRow(from)->baseline()); } -void LyXText::Delete(BufferView * bview) +void LyXText::Delete() { // this is a very easy implementation 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(bview); + cursorRight(bv()); // CHECK Look at the comment here. // This check is not very good... @@ -2396,7 +2320,7 @@ void LyXText::Delete(BufferView * bview) // 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 @@ -2408,20 +2332,19 @@ void LyXText::Delete(BufferView * bview) LyXCursor tmpcursor = cursor; // to make sure undo gets the right cursor position cursor = old_cursor; - setUndo(bview, Undo::DELETE, - cursor.par(), cursor.par()->next()); + setUndo(bv(), Undo::DELETE, cursor.par()); cursor = tmpcursor; - backspace(bview); + backspace(); } } -void LyXText::backspace(BufferView * bview) +void LyXText::backspace() { // Get the font that is used to calculate the baselineskip pos_type lastpos = cursor.par()->size(); LyXFont rawparfont = - cursor.par()->getFontSettings(bview->buffer()->params, + cursor.par()->getFontSettings(bv()->buffer()->params, lastpos - 1); if (cursor.pos() == 0) { @@ -2442,47 +2365,46 @@ void LyXText::backspace(BufferView * bview) // 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(bview); + cursorLeft(bv()); // the layout things can change the height of a row ! - int const tmpheight = cursor.row()->height(); - setHeightOfRow(bview, cursor.row()); - if (cursor.row()->height() != tmpheight) { - refresh_y = cursor.y() - cursor.row()->baseline(); - refresh_row = cursor.row(); - status(bview, LyXText::NEED_MORE_REFRESH); + int const tmpheight = cursorRow()->height(); + setHeightOfRow(cursorRow()); + if (cursorRow()->height() != tmpheight) { + postPaint(cursor.y() - cursorRow()->baseline()); } return; } } - if (cursor.par()->previous()) { - setUndo(bview, Undo::DELETE, - cursor.par()->previous(), cursor.par()->next()); + if (cursor.par() != ownerParagraphs().begin()) { + setUndo(bv(), Undo::DELETE, + 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(bview, cursor.par()->previous(), - cursor.par()->previous()->size(), + setCursorIntern(boost::prior(cursor.par()), + boost::prior(cursor.par())->size(), false); } @@ -2496,15 +2418,15 @@ void LyXText::backspace(BufferView * bview) // Correction: Pasting is always allowed with standard-layout LyXTextClass const & tclass = - bview->buffer()->params.getLyXTextClass(); + 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(bview->buffer()->params, bview->buffer()->paragraphs, cursor.par()); + mergeParagraph(bv()->buffer()->params, bv()->buffer()->paragraphs, cursor.par()); if (!cursor.pos() || !cursor.par()->isSeparator(cursor.pos() - 1)) ; //cursor.par()->insertChar(cursor.pos(), ' '); @@ -2515,9 +2437,7 @@ void LyXText::backspace(BufferView * bview) if (cursor.pos()) cursor.pos(cursor.pos() - 1); - status(bview, LyXText::NEED_MORE_REFRESH); - refresh_row = cursor.row(); - refresh_y = 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 @@ -2528,22 +2448,21 @@ void LyXText::backspace(BufferView * bview) //RemoveRow(tmprow); // This rebuilds the rows. - appendParagraph(bview, cursor.row()); - updateCounters(bview); + appendParagraph(cursorRow()); + updateCounters(); // the row may have changed, block, hfills etc. - setCursor(bview, cursor.par(), cursor.pos(), false); + setCursor(cursor.par(), cursor.pos(), false); } } else { // this is the code for a normal backspace, not pasting // any paragraphs - setUndo(bview, 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, // without the dreaded mechanism. (JMarc) - setCursorIntern(bview, cursor.par(), cursor.pos()- 1, + setCursorIntern(cursor.par(), cursor.pos()- 1, false, cursor.boundary()); if (cursor.par()->isInset(cursor.pos())) { @@ -2552,19 +2471,19 @@ void LyXText::backspace(BufferView * bview) if (cursor.par()->getInset(cursor.pos())->display() || cursor.par()->getInset(cursor.pos())->needFullRow()) { cursor.par()->erase(cursor.pos()); - redoParagraph(bview); + redoParagraph(); return; } } - 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(bview, + row->fill(row->fill() + singleWidth( cursor.par(), cursor.pos())); } @@ -2574,9 +2493,10 @@ void LyXText::backspace(BufferView * bview) 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)) @@ -2585,12 +2505,13 @@ void LyXText::backspace(BufferView * bview) if (cursor.pos() < cursor.par()->size() && !cursor.par()->isSeparator(cursor.pos())) { cursor.par()->insertChar(cursor.pos(), ' '); - setCharFont(bview->buffer(), cursor.par(), + setCharFont(bv()->buffer(), cursor.par(), 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); } } @@ -2598,222 +2519,248 @@ void LyXText::backspace(BufferView * bview) 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); } // delete newlines at the beginning of paragraphs while (!cursor.par()->empty() && + cursor.pos() < cursor.par()->size() && cursor.par()->isNewline(cursor.pos()) && cursor.pos() == cursor.par()->beginningOfBody()) { 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(*bview, *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()) { // remove it removeRow(row); - need_break_row = 0; + need_break_row = rows().end(); } else { - breakAgainOneRow(bview, row); - if (row->next() && row->next()->par() == row->par()) - need_break_row = row->next(); + breakAgainOneRow(row); + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par()) + need_break_row = boost::next(row); else - need_break_row = 0; + need_break_row = rows().end(); } // set the dimensions of the row above y -= tmprow->height(); - tmprow->fill(fill(*bview, *tmprow, workWidth(*bview))); - setHeightOfRow(bview, tmprow); + tmprow->fill(fill(tmprow, workWidth())); + setHeightOfRow(tmprow); - refresh_y = y; - refresh_row = tmprow; - status(bview, LyXText::NEED_MORE_REFRESH); - setCursor(bview, cursor.par(), cursor.pos(), + postPaint(y); + + setCursor(cursor.par(), cursor.pos(), false, cursor.boundary()); //current_font = rawtmpfont; //real_current_font = realtmpfont; // check, whether the last character's font has changed. if (rawparfont != - cursor.par()->getFontSettings(bview->buffer()->params, + cursor.par()->getFontSettings(bv()->buffer()->params, cursor.par()->size() - 1)) - redoHeightOfParagraph(bview, cursor); + redoHeightOfParagraph(); return; } } // break the cursor row again - if (row->next() && row->next()->par() == row->par() && - (row->lastPos() == row->par()->size() - 1 || - rowBreakPoint(*bview, *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)); - refresh_y = y; - refresh_row = row; - status(bview, LyXText::NEED_MORE_REFRESH); + postPaint(y); - breakAgainOneRow(bview, row); + 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(); - breakAgainOneRow(bview, row); + if (boost::next(row) != rows().end() && + boost::next(row)->par() == row->par() && + lastPos(*this, row) <= cursor.pos()) { + ++row; + breakAgainOneRow(row); } - setCursor(bview, cursor.par(), cursor.pos(), false, cursor.boundary()); + 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 = 0; + need_break_row = rows().end(); } else { // set the dimensions of the row - row->fill(fill(*bview, *row, workWidth(*bview))); + row->fill(fill(row, workWidth())); int const tmpheight = row->height(); - setHeightOfRow(bview, row); - if (tmpheight == row->height()) - status(bview, LyXText::NEED_VERY_LITTLE_REFRESH); - else - status(bview, LyXText::NEED_MORE_REFRESH); - refresh_y = y; - refresh_row = row; - setCursor(bview, cursor.par(), cursor.pos(), false, cursor.boundary()); + setHeightOfRow(row); + if (tmpheight == row->height()) { + postRowPaint(row, y); + } else { + postPaint(y); + } + setCursor(cursor.par(), cursor.pos(), false, cursor.boundary()); } } // current_font = rawtmpfont; // real_current_font = realtmpfont; - if (isBoundary(bview->buffer(), cursor.par(), cursor.pos()) + if (isBoundary(bv()->buffer(), *cursor.par(), cursor.pos()) != cursor.boundary()) - setCursor(bview, cursor.par(), cursor.pos(), false, + setCursor(cursor.par(), cursor.pos(), false, !cursor.boundary()); lastpos = cursor.par()->size(); if (cursor.pos() == lastpos) - setCurrentFont(bview); + setCurrentFont(); // check, whether the last characters font has changed. if (rawparfont != - cursor.par()->getFontSettings(bview->buffer()->params, lastpos - 1)) { - redoHeightOfParagraph(bview, cursor); + cursor.par()->getFontSettings(bv()->buffer()->params, lastpos - 1)) { + redoHeightOfParagraph(); } else { // now the special right address boxes if (cursor.par()->layout()->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - redoDrawingOfParagraph(bview, cursor); + redoDrawingOfParagraph(cursor); } } } -// returns pointer to a specified row -Row * LyXText::getRow(Paragraph * par, pos_type pos, int & y) const +RowList::iterator LyXText::cursorRow() const { - if (!firstrow) - return 0; + return getRow(cursor.par(), cursor.pos()); +} - Row * tmprow = firstrow; - y = 0; + +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 - while (tmprow->next() && tmprow->par() != par) { - y += tmprow->height(); - tmprow = tmprow->next(); + 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 (tmprow->pos() < pos - && tmprow->next() - && tmprow->next()->par() == par - && tmprow->next()->pos() <= pos) { - y += tmprow->height(); - tmprow = tmprow->next(); + while (rit->pos() < pos + && boost::next(rit) != end + && boost::next(rit)->par() == pit + && boost::next(rit)->pos() <= pos) { + ++rit; } - return tmprow; + return rit; } - -Row * LyXText::getRowNearY(int & y) const +// returns pointer to a specified row +RowList::iterator +LyXText::getRow(ParagraphList::iterator pit, pos_type pos, int & y) const { -#if 1 - // If possible we should optimize this method. (Lgb) - Row * tmprow = firstrow; - int tmpy = 0; + y = 0; - while (tmprow->next() && tmpy + tmprow->height() <= y) { - tmpy += tmprow->height(); - tmprow = tmprow->next(); + 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) { + y += rit->height(); + ++rit; } - y = tmpy; // return the real y + // now find the wanted row + while (rit->pos() < pos + && boost::next(rit) != end + && boost::next(rit)->par() == pit + && boost::next(rit)->pos() <= pos) { + y += rit->height(); + ++rit; + } + + return rit; +} - //lyxerr << "returned y = " << y << endl; - return tmprow; -#else - // Search from the current cursor position. +RowList::iterator LyXText::getRowNearY(int & y) const +{ - Row * tmprow = cursor.row(); - int tmpy = cursor.y() - tmprow->baseline(); + RowList::iterator rit = anchor_row_; + RowList::iterator const beg = rows().begin(); + RowList::iterator const end = rows().end(); - lyxerr << "cursor.y() = " << tmpy << endl; - lyxerr << "tmprow->height() = " << tmprow->height() << endl; - lyxerr << "tmprow->baseline() = " << tmprow->baseline() << endl; - lyxerr << "first = " << first << endl; - lyxerr << "y = " << y << endl; + if (rows().empty()) { + y = 0; + return end; + } + if (rit == end) + rit = beg; - if (y < tmpy) { - lyxerr << "up" << endl; - do { - tmpy -= tmprow->height(); - tmprow = tmprow->previous(); - } while (tmprow && tmpy - tmprow->height() >= y); - } else if (y > tmpy) { - lyxerr << "down" << endl; + int tmpy = rit->y(); - while (tmprow->next() && tmpy + tmprow->height() <= y) { - tmpy += tmprow->height(); - tmprow = tmprow->next(); + if (tmpy <= y) { + while (rit != end && tmpy <= y) { + tmpy += rit->height(); + ++rit; + } + if (rit != beg) { + --rit; + tmpy -= rit->height(); } } else { - lyxerr << "equal" << endl; + while (rit != beg && tmpy > y) { + --rit; + tmpy -= rit->height(); + } + } + if (tmpy < 0 || rit == end) { + tmpy = 0; + rit = beg; } - y = tmpy; // return the real y - - lyxerr << "returned y = " << y << endl; - - return tmprow; + // return the rel y + y = tmpy; -#endif + return rit; }