X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext2.C;h=673287fbbb595796f0fedb4242fbf7cb15b9ebde;hb=3c851f1f7951f3a24b57826f3e580e4318b5e6c4;hp=fc52daaf6d3f1f2c3547af2c72e65fd37ef90026;hpb=02291d14f1e07e92af7f8962f0818f99046b1df1;p=lyx.git diff --git a/src/text2.C b/src/text2.C index fc52daaf6d..673287fbbb 100644 --- a/src/text2.C +++ b/src/text2.C @@ -27,6 +27,7 @@ #include "BufferView.h" #include "Bullet.h" #include "counters.h" +#include "coordcache.h" #include "cursor.h" #include "CutAndPaste.h" #include "debug.h" @@ -44,7 +45,6 @@ #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" -#include "PosIterator.h" #include "undo.h" #include "vspace.h" @@ -58,11 +58,11 @@ #include "support/lstrings.h" #include "support/textutils.h" -#include "support/tostr.h" -#include "support/std_sstream.h" +#include "support/convert.h" -#include +#include +using lyx::pit_type; using lyx::pos_type; using lyx::support::bformat; @@ -71,52 +71,95 @@ using std::ostringstream; using std::string; -LyXText::LyXText(BufferView * bv, bool in_inset) - : height(0), width(0), textwidth_(bv ? bv->workWidth() : 100), - background_color_(LColor::background), - bv_owner(bv), in_inset_(in_inset), xo_(0), yo_(0) +LyXText::LyXText(BufferView * bv) + : maxwidth_(bv ? bv->workWidth() : 100), + background_color_(LColor::background), + bv_owner(bv), + autoBreakRows_(false) {} void LyXText::init(BufferView * bv) { + BOOST_ASSERT(bv); bv_owner = bv; + maxwidth_ = bv->workWidth(); + dim_.wid = maxwidth_; + dim_.asc = 10; + dim_.des = 10; - ParagraphList::iterator const beg = paragraphs().begin(); - ParagraphList::iterator const end = paragraphs().end(); - for (ParagraphList::iterator pit = beg; pit != end; ++pit) - pit->rows.clear(); + pit_type const end = paragraphs().size(); + for (pit_type pit = 0; pit != end; ++pit) + pars_[pit].rows().clear(); - width = 0; - height = 0; + current_font = getFont(pars_[0], 0); + updateCounters(); +} - current_font = getFont(beg, 0); - redoParagraphs(beg, end); - bv->cursor().resetAnchor(); +bool LyXText::isMainText() const +{ + return &bv()->buffer()->text() == this; +} - updateCounters(); + +//takes screen x,y coordinates +InsetBase * LyXText::checkInsetHit(int x, int y) const +{ + pit_type pit = getPitNearY(y); + BOOST_ASSERT(pit != -1); + + Paragraph const & par = pars_[pit]; + + lyxerr << "checkInsetHit: x: " << x << " y: " << y << endl; + lyxerr << " pit: " << pit << endl; + InsetList::const_iterator iit = par.insetlist.begin(); + InsetList::const_iterator iend = par.insetlist.end(); + for (; iit != iend; ++iit) { + InsetBase * inset = iit->inset; +#if 1 + lyxerr << "examining inset " << inset << endl; + if (theCoords.getInsets().has(inset)) + lyxerr + << " xo: " << inset->xo() << "..." + << inset->xo() + inset->width() + << " yo: " << inset->yo() - inset->ascent() + << "..." + << inset->yo() + inset->descent() << endl; + else + lyxerr << " inset has no cached position" << endl; +#endif + if (inset->covers(x, y)) { + lyxerr << "Hit inset: " << inset << endl; + return inset; + } + } + lyxerr << "No inset hit. " << endl; + return 0; } + // Gets the fully instantiated font at a given position in a paragraph // Basically the same routine as Paragraph::getFont() in paragraph.C. // The difference is that this one is used for displaying, and thus we // are allowed to make cosmetic improvements. For instance make footnotes // smaller. (Asger) -LyXFont LyXText::getFont(ParagraphList::iterator pit, pos_type pos) const +LyXFont LyXText::getFont(Paragraph const & par, pos_type const pos) const { BOOST_ASSERT(pos >= 0); - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = par.layout(); +#ifdef WITH_WARNINGS #warning broken? +#endif BufferParams const & params = bv()->buffer()->params(); - pos_type const body_pos = pit->beginOfBody(); + pos_type const body_pos = par.beginOfBody(); // We specialize the 95% common case: - if (!pit->getDepth()) { - LyXFont f = pit->getFontSettings(params, pos); - if (in_inset_) + if (!par.getDepth()) { + LyXFont f = par.getFontSettings(params, pos); + if (!isMainText()) f.realize(font_); if (layout->labeltype == LABEL_MANUAL && pos < body_pos) return f.realize(layout->reslabelfont); @@ -131,25 +174,24 @@ LyXFont LyXText::getFont(ParagraphList::iterator pit, pos_type pos) const else layoutfont = layout->font; - LyXFont font = pit->getFontSettings(params, pos); + LyXFont font = par.getFontSettings(params, pos); font.realize(layoutfont); - if (in_inset_) + if (!isMainText()) font.realize(font_); // Realize with the fonts of lesser depth. - //font.realize(outerFont(pit, paragraphs())); font.realize(defaultfont_); return font; } -LyXFont LyXText::getLayoutFont(ParagraphList::iterator pit) const +LyXFont LyXText::getLayoutFont(pit_type const pit) const { - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = pars_[pit].layout(); - if (!pit->getDepth()) + if (!pars_[pit].getDepth()) return layout->resfont; LyXFont font = layout->font; @@ -161,45 +203,43 @@ LyXFont LyXText::getLayoutFont(ParagraphList::iterator pit) const } -LyXFont LyXText::getLabelFont(ParagraphList::iterator pit) const +LyXFont LyXText::getLabelFont(Paragraph const & par) const { - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = par.layout(); - if (!pit->getDepth()) + if (!par.getDepth()) return layout->reslabelfont; LyXFont font = layout->labelfont; // Realize with the fonts of lesser depth. - font.realize(outerFont(pit, paragraphs())); font.realize(defaultfont_); return font; } -void LyXText::setCharFont( - ParagraphList::iterator pit, pos_type pos, LyXFont const & fnt) +void LyXText::setCharFont(pit_type pit, pos_type pos, LyXFont const & fnt) { LyXFont font = fnt; - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = pars_[pit].layout(); // Get concrete layout font to reduce against LyXFont layoutfont; - if (pos < pit->beginOfBody()) + if (pos < pars_[pit].beginOfBody()) layoutfont = layout->labelfont; else layoutfont = layout->font; // Realize against environment font information - if (pit->getDepth()) { - ParagraphList::iterator tp = pit; + if (pars_[pit].getDepth()) { + pit_type tp = pit; while (!layoutfont.resolved() && - tp != paragraphs().end() && - tp->getDepth()) { + tp != pit_type(paragraphs().size()) && + pars_[tp].getDepth()) { tp = outerHook(tp, paragraphs()); - if (tp != paragraphs().end()) - layoutfont.realize(tp->layout()->font); + if (tp != pit_type(paragraphs().size())) + layoutfont.realize(pars_[tp].layout()->font); } } @@ -208,7 +248,7 @@ void LyXText::setCharFont( // Now, reduce font against full layout font font.reduce(layoutfont); - pit->setFont(pos, font); + pars_[pit].setFont(pos, font); } @@ -235,42 +275,38 @@ void LyXText::makeFontEntriesLayoutSpecific(BufferParams const & params, // return past-the-last paragraph influenced by a layout change on pit -ParagraphList::iterator LyXText::undoSpan(ParagraphList::iterator pit) +pit_type LyXText::undoSpan(pit_type pit) { - ParagraphList::iterator end = paragraphs().end(); - ParagraphList::iterator nextpit = boost::next(pit); + pit_type end = paragraphs().size(); + pit_type nextpit = pit + 1; if (nextpit == end) return nextpit; //because of parindents - if (!pit->getDepth()) + if (!pars_[pit].getDepth()) return boost::next(nextpit); //because of depth constrains for (; nextpit != end; ++pit, ++nextpit) { - if (!pit->getDepth()) + if (!pars_[pit].getDepth()) break; } return nextpit; } -ParagraphList::iterator -LyXText::setLayout(ParagraphList::iterator start, - ParagraphList::iterator end, - string const & layout) +pit_type LyXText::setLayout(pit_type start, pit_type end, string const & layout) { BOOST_ASSERT(start != end); - ParagraphList::iterator undopit = undoSpan(boost::prior(end)); - recUndo(parOffset(start), parOffset(undopit) - 1); + pit_type undopit = undoSpan(end - 1); + recUndo(start, undopit - 1); BufferParams const & bufparams = bv()->buffer()->params(); - LyXLayout_ptr const & lyxlayout = - bufparams.getLyXTextClass()[layout]; + LyXLayout_ptr const & lyxlayout = bufparams.getLyXTextClass()[layout]; - for (ParagraphList::iterator pit = start; pit != end; ++pit) { - pit->applyLayout(lyxlayout); - makeFontEntriesLayoutSpecific(bufparams, *pit); + for (pit_type pit = start; pit != end; ++pit) { + pars_[pit].applyLayout(lyxlayout); + makeFontEntriesLayoutSpecific(bufparams, pars_[pit]); if (lyxlayout->margintype == MARGIN_MANUAL) - pit->setLabelWidthString(lyxlayout->labelstring()); + pars_[pit].setLabelWidthString(lyxlayout->labelstring()); } return undopit; @@ -282,25 +318,25 @@ void LyXText::setLayout(LCursor & cur, string const & layout) { BOOST_ASSERT(this == cur.text()); // special handling of new environment insets - BufferParams const & params = bv()->buffer()->params(); + BufferView & bv = cur.bv(); + BufferParams const & params = bv.buffer()->params(); LyXLayout_ptr const & lyxlayout = params.getLyXTextClass()[layout]; if (lyxlayout->is_environment) { // move everything in a new environment inset - lyxerr << "setting layout " << layout << endl; - bv()->owner()->dispatch(FuncRequest(LFUN_HOME)); - bv()->owner()->dispatch(FuncRequest(LFUN_ENDSEL)); - bv()->owner()->dispatch(FuncRequest(LFUN_CUT)); + lyxerr[Debug::DEBUG] << "setting layout " << layout << endl; + bv.owner()->dispatch(FuncRequest(LFUN_HOME)); + bv.owner()->dispatch(FuncRequest(LFUN_ENDSEL)); + bv.owner()->dispatch(FuncRequest(LFUN_CUT)); InsetBase * inset = new InsetEnvironment(params, layout); insertInset(cur, inset); //inset->edit(cur, true); - //bv()->owner()->dispatch(FuncRequest(LFUN_PASTE)); + //bv.owner()->dispatch(FuncRequest(LFUN_PASTE)); return; } - ParagraphList::iterator start = getPar(cur.selBegin().par()); - ParagraphList::iterator end = boost::next(getPar(cur.selEnd().par())); - ParagraphList::iterator endpit = setLayout(start, end, layout); - redoParagraphs(start, endpit); + pit_type start = cur.selBegin().pit(); + pit_type end = cur.selEnd().pit() + 1; + setLayout(start, end, layout); updateCounters(); } @@ -308,30 +344,15 @@ void LyXText::setLayout(LCursor & cur, string const & layout) namespace { -void getSelectionSpan(LCursor & cur, LyXText & text, - ParagraphList::iterator & beg, - ParagraphList::iterator & end) -{ - if (!cur.selection()) { - beg = text.getPar(cur.par()); - end = boost::next(beg); - } else { - beg = text.getPar(cur.selBegin()); - end = boost::next(text.getPar(cur.selEnd())); - } -} - - -bool changeDepthAllowed(bv_funcs::DEPTH_CHANGE type, - Paragraph const & par, - int max_depth) +bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, + Paragraph const & par, int max_depth) { if (par.layout()->labeltype == LABEL_BIBLIO) return false; int const depth = par.params().depth(); - if (type == bv_funcs::INC_DEPTH && depth < max_depth) + if (type == LyXText::INC_DEPTH && depth < max_depth) return true; - if (type == bv_funcs::DEC_DEPTH && depth > 0) + if (type == LyXText::DEC_DEPTH && depth > 0) return true; return false; } @@ -340,44 +361,40 @@ bool changeDepthAllowed(bv_funcs::DEPTH_CHANGE type, } -bool LyXText::changeDepthAllowed(LCursor & cur, bv_funcs::DEPTH_CHANGE type) +bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const { BOOST_ASSERT(this == cur.text()); - ParagraphList::iterator beg, end; - getSelectionSpan(cur, *this, beg, end); - int max_depth = 0; - if (beg != paragraphs().begin()) - max_depth = boost::prior(beg)->getMaxDepthAfter(); - - for (ParagraphList::iterator pit = beg; pit != end; ++pit) { - if (::changeDepthAllowed(type, *pit, max_depth)) + pit_type const beg = cur.selBegin().pit(); + pit_type const end = cur.selEnd().pit() + 1; + int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0); + + for (pit_type pit = beg; pit != end; ++pit) { + if (::changeDepthAllowed(type, pars_[pit], max_depth)) return true; - max_depth = pit->getMaxDepthAfter(); + max_depth = pars_[pit].getMaxDepthAfter(); } return false; } -void LyXText::changeDepth(LCursor & cur, bv_funcs::DEPTH_CHANGE type) +void LyXText::changeDepth(LCursor & cur, DEPTH_CHANGE type) { BOOST_ASSERT(this == cur.text()); - ParagraphList::iterator beg, end; - getSelectionSpan(cur, *this, beg, end); + pit_type const beg = cur.selBegin().pit(); + pit_type const end = cur.selEnd().pit() + 1; recordUndoSelection(cur); - - int max_depth = 0; - if (beg != paragraphs().begin()) - max_depth = boost::prior(beg)->getMaxDepthAfter(); - - for (ParagraphList::iterator pit = beg; pit != end; ++pit) { - if (::changeDepthAllowed(type, *pit, max_depth)) { - int const depth = pit->params().depth(); - if (type == bv_funcs::INC_DEPTH) - pit->params().depth(depth + 1); + int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0); + + for (pit_type pit = beg; pit != end; ++pit) { + Paragraph & par = pars_[pit]; + if (::changeDepthAllowed(type, par, max_depth)) { + int const depth = par.params().depth(); + if (type == INC_DEPTH) + par.params().depth(depth + 1); else - pit->params().depth(depth - 1); + par.params().depth(depth - 1); } - max_depth = pit->getMaxDepthAfter(); + max_depth = par.getMaxDepthAfter(); } // this handles the counter labels, and also fixes up // depth values for follow-on (child) paragraphs @@ -385,7 +402,7 @@ void LyXText::changeDepth(LCursor & cur, bv_funcs::DEPTH_CHANGE type) } -// set font over selection and make a total rebreak of those paragraphs +// set font over selection void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) { BOOST_ASSERT(this == cur.text()); @@ -393,15 +410,15 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) if (!cur.selection()) { // Determine basis font LyXFont layoutfont; - ParagraphList::iterator pit = getPar(cur.par()); - if (cur.pos() < pit->beginOfBody()) - layoutfont = getLabelFont(pit); + pit_type pit = cur.pit(); + if (cur.pos() < pars_[pit].beginOfBody()) + layoutfont = getLabelFont(pars_[pit]); else layoutfont = getLayoutFont(pit); // Update current font real_current_font.update(font, - bv()->buffer()->params().language, + cur.buffer().params().language, toggleall); // Reduce to implicit settings @@ -413,27 +430,25 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) return; } - // ok we have a selection. + // Ok, we have a selection. recordUndoSelection(cur); - freezeUndo(); - ParagraphList::iterator beg = getPar(cur.selBegin().par()); - ParagraphList::iterator end = getPar(cur.selEnd().par()); - - PosIterator pos(¶graphs(), beg, cur.selBegin().pos()); - PosIterator posend(¶graphs(), end, cur.selEnd().pos()); + DocIterator dit = cur.selectionBegin(); + DocIterator ditend = cur.selectionEnd(); - BufferParams const & params = bv()->buffer()->params(); + BufferParams const & params = cur.buffer().params(); - for (; pos != posend; ++pos) { - LyXFont f = getFont(pos.pit(), pos.pos()); - f.update(font, params.language, toggleall); - setCharFont(pos.pit(), pos.pos(), f); + // Don't use forwardChar here as ditend might have + // pos() == lastpos() and forwardChar would miss it. + // Can't use forwardPos either as this descends into + // nested insets. + for (; dit != ditend; dit.forwardPosNoDescend()) { + if (dit.pos() != dit.lastpos()) { + LyXFont f = getFont(dit.paragraph(), dit.pos()); + f.update(font, params.language, toggleall); + setCharFont(dit.pit(), dit.pos(), f); + } } - - unFreezeUndo(); - - redoParagraphs(beg, ++end); } @@ -443,7 +458,7 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) void LyXText::cursorHome(LCursor & cur) { BOOST_ASSERT(this == cur.text()); - setCursor(cur, cur.par(), cur.textRow().pos()); + setCursor(cur, cur.pit(), cur.textRow().pos()); } @@ -452,8 +467,9 @@ void LyXText::cursorEnd(LCursor & cur) BOOST_ASSERT(this == cur.text()); // if not on the last row of the par, put the cursor before // the final space +// FIXME: does this final space exist? pos_type const end = cur.textRow().endpos(); - setCursor(cur, cur.par(), end == cur.lastpos() ? end : end - 1); + setCursor(cur, cur.pit(), end == cur.lastpos() ? end : end - 1); } @@ -467,7 +483,7 @@ void LyXText::cursorTop(LCursor & cur) void LyXText::cursorBottom(LCursor & cur) { BOOST_ASSERT(this == cur.text()); - setCursor(cur, cur.lastpar(), boost::prior(paragraphs().end())->size()); + setCursor(cur, cur.lastpit(), boost::prior(paragraphs().end())->size()); } @@ -485,7 +501,7 @@ void LyXText::toggleFree(LCursor & cur, LyXFont const & font, bool toggleall) // Try implicit word selection // If there is a change in the language the implicit word selection // is disabled. - CursorSlice resetCursor = cur.current(); + CursorSlice resetCursor = cur.top(); bool implicitSelection = font.language() == ignore_language && font.number() == LyXFont::IGNORE @@ -498,7 +514,7 @@ void LyXText::toggleFree(LCursor & cur, LyXFont const & font, bool toggleall) // and cursor is set to the original position. if (implicitSelection) { cur.clearSelection(); - cur.current() = resetCursor; + cur.top() = resetCursor; cur.resetAnchor(); } } @@ -510,20 +526,20 @@ string LyXText::getStringToIndex(LCursor & cur) // Try implicit word selection // If there is a change in the language the implicit word selection // is disabled. - CursorSlice const reset_cursor = cur.current(); + CursorSlice const reset_cursor = cur.top(); bool const implicitSelection = selectWordWhenUnderCursor(cur, lyx::PREVIOUS_WORD); string idxstring; if (!cur.selection()) cur.message(_("Nothing to index!")); - else if (cur.selBegin().par() != cur.selEnd().par()) + else if (cur.selBegin().pit() != cur.selEnd().pit()) cur.message(_("Cannot index more than one paragraph!")); else idxstring = cur.selectionAsString(false); // Reset cursors to their original position. - cur.current() = reset_cursor; + cur.top() = reset_cursor; cur.resetAnchor(); // Clear the implicit selection. @@ -534,30 +550,23 @@ string LyXText::getStringToIndex(LCursor & cur) } -// the DTP switches for paragraphs(). LyX will store them in the first -// physical paragraph. When a paragraph is broken, the top settings rest, -// the bottom settings are given to the new one. So I can make sure, -// they do not duplicate themself and you cannot play dirty tricks with -// them! - void LyXText::setParagraph(LCursor & cur, Spacing const & spacing, LyXAlignment align, string const & labelwidthstring, bool noindent) { BOOST_ASSERT(cur.text()); // make sure that the depth behind the selection are restored, too - ParagraphList::iterator undopit = undoSpan(getPar(cur.selEnd())); - recUndo(cur.selBegin().par(), parOffset(undopit) - 1); + pit_type undopit = undoSpan(cur.selEnd().pit()); + recUndo(cur.selBegin().pit(), undopit - 1); - ParagraphList::reverse_iterator pit(getPar(cur.selEnd().par())); - ParagraphList::reverse_iterator beg(getPar(cur.selBegin().par())); - - for (--pit; pit != beg; ++pit) { - ParagraphParameters & params = pit->params(); + for (pit_type pit = cur.selBegin().pit(), end = cur.selEnd().pit(); + pit <= end; ++pit) { + Paragraph & par = pars_[pit]; + ParagraphParameters & params = par.params(); params.spacing(spacing); // does the layout allow the new alignment? - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = par.layout(); if (align == LYX_ALIGN_LAYOUT) align = layout->align; @@ -567,11 +576,9 @@ void LyXText::setParagraph(LCursor & cur, else params.align(align); } - pit->setLabelWidthString(labelwidthstring); + par.setLabelWidthString(labelwidthstring); params.noindent(noindent); } - - redoParagraphs(getPar(cur.selBegin()), undopit); } @@ -599,33 +606,32 @@ string expandLabel(LyXTextClass const & textclass, namespace { -void incrementItemDepth(ParagraphList::iterator pit, - ParagraphList::iterator first_pit) +void incrementItemDepth(ParagraphList & pars, pit_type pit, pit_type first_pit) { - int const cur_labeltype = pit->layout()->labeltype; + int const cur_labeltype = pars[pit].layout()->labeltype; if (cur_labeltype != LABEL_ENUMERATE && cur_labeltype != LABEL_ITEMIZE) return; - int const cur_depth = pit->getDepth(); + int const cur_depth = pars[pit].getDepth(); - ParagraphList::iterator prev_pit = boost::prior(pit); + pit_type prev_pit = pit - 1; while (true) { - int const prev_depth = prev_pit->getDepth(); - int const prev_labeltype = prev_pit->layout()->labeltype; + int const prev_depth = pars[prev_pit].getDepth(); + int const prev_labeltype = pars[prev_pit].layout()->labeltype; if (prev_depth == 0 && cur_depth > 0) { if (prev_labeltype == cur_labeltype) { - pit->itemdepth = prev_pit->itemdepth + 1; + pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; } break; } else if (prev_depth < cur_depth) { if (prev_labeltype == cur_labeltype) { - pit->itemdepth = prev_pit->itemdepth + 1; + pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; break; } } else if (prev_depth == cur_depth) { if (prev_labeltype == cur_labeltype) { - pit->itemdepth = prev_pit->itemdepth; + pars[pit].itemdepth = pars[prev_pit].itemdepth; break; } } @@ -637,21 +643,20 @@ void incrementItemDepth(ParagraphList::iterator pit, } -void resetEnumCounterIfNeeded(ParagraphList::iterator pit, - ParagraphList::iterator firstpit, - Counters & counters) +void resetEnumCounterIfNeeded(ParagraphList & pars, pit_type pit, + pit_type firstpit, Counters & counters) { if (pit == firstpit) return; - int const cur_depth = pit->getDepth(); - ParagraphList::iterator prev_pit = boost::prior(pit); + int const cur_depth = pars[pit].getDepth(); + pit_type prev_pit = pit - 1; while (true) { - int const prev_depth = prev_pit->getDepth(); - int const prev_labeltype = prev_pit->layout()->labeltype; + int const prev_depth = pars[prev_pit].getDepth(); + int const prev_labeltype = pars[prev_pit].layout()->labeltype; if (prev_depth <= cur_depth) { if (prev_labeltype != LABEL_ENUMERATE) { - switch (pit->itemdepth) { + switch (pars[pit].itemdepth) { case 0: counters.reset("enumi"); case 1: @@ -676,39 +681,39 @@ void resetEnumCounterIfNeeded(ParagraphList::iterator pit, // set the counter of a paragraph. This includes the labels -void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) +void LyXText::setCounter(Buffer const & buf, pit_type pit) { + Paragraph & par = pars_[pit]; BufferParams const & bufparams = buf.params(); LyXTextClass const & textclass = bufparams.getLyXTextClass(); - LyXLayout_ptr const & layout = pit->layout(); - ParagraphList::iterator first_pit = paragraphs().begin(); + LyXLayout_ptr const & layout = par.layout(); Counters & counters = textclass.counters(); // Always reset - pit->itemdepth = 0; + par.itemdepth = 0; - if (pit == first_pit) { - pit->params().appendix(pit->params().startOfAppendix()); + if (pit == 0) { + par.params().appendix(par.params().startOfAppendix()); } else { - pit->params().appendix(boost::prior(pit)->params().appendix()); - if (!pit->params().appendix() && - pit->params().startOfAppendix()) { - pit->params().appendix(true); + par.params().appendix(pars_[pit - 1].params().appendix()); + if (!par.params().appendix() && + par.params().startOfAppendix()) { + par.params().appendix(true); textclass.counters().reset(); } // Maybe we have to increment the item depth. - incrementItemDepth(pit, first_pit); + incrementItemDepth(pars_, pit, 0); } // erase what was there before - pit->params().labelString(string()); + par.params().labelString(string()); if (layout->margintype == MARGIN_MANUAL) { - if (pit->params().labelWidthString().empty()) - pit->setLabelWidthString(layout->labelstring()); + if (par.params().labelWidthString().empty()) + par.setLabelWidthString(layout->labelstring()); } else { - pit->setLabelWidthString(string()); + par.setLabelWidthString(string()); } // is it a layout that has an automatic label? @@ -716,16 +721,16 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) BufferParams const & bufparams = buf.params(); LyXTextClass const & textclass = bufparams.getLyXTextClass(); counters.step(layout->counter); - string label = expandLabel(textclass, layout, pit->params().appendix()); - pit->params().labelString(label); + string label = expandLabel(textclass, layout, par.params().appendix()); + par.params().labelString(label); } else if (layout->labeltype == LABEL_ITEMIZE) { // At some point of time we should do something more // clever here, like: - // pit->params().labelString( - // bufparams.user_defined_bullet(pit->itemdepth).getText()); + // par.params().labelString( + // bufparams.user_defined_bullet(par.itemdepth).getText()); // for now, use a simple hardcoded label string itemlabel; - switch (pit->itemdepth) { + switch (par.itemdepth) { case 0: itemlabel = "*"; break; @@ -740,17 +745,17 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) break; } - pit->params().labelString(itemlabel); + par.params().labelString(itemlabel); } else if (layout->labeltype == LABEL_ENUMERATE) { // Maybe we have to reset the enumeration counter. - resetEnumCounterIfNeeded(pit, first_pit, counters); + resetEnumCounterIfNeeded(pars_, pit, 0, counters); // FIXME // Yes I know this is a really, really! bad solution // (Lgb) string enumcounter = "enum"; - switch (pit->itemdepth) { + switch (par.itemdepth) { case 2: enumcounter += 'i'; case 1: @@ -768,13 +773,13 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) counters.step(enumcounter); - pit->params().labelString(counters.enumLabel(enumcounter)); + par.params().labelString(counters.enumLabel(enumcounter)); } else if (layout->labeltype == LABEL_BIBLIO) {// ale970302 counters.step("bibitem"); int number = counters.value("bibitem"); - if (pit->bibitem()) { - pit->bibitem()->setCounter(number); - pit->params().labelString(layout->labelstring()); + if (par.bibitem()) { + par.bibitem()->setCounter(number); + par.params().labelString(layout->labelstring()); } // In biblio should't be following counters but... } else { @@ -782,25 +787,39 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) // the caption hack: if (layout->labeltype == LABEL_SENSITIVE) { - ParagraphList::iterator end = paragraphs().end(); - ParagraphList::iterator tmppit = pit; + pit_type end = paragraphs().size(); + pit_type tmppit = pit; InsetBase * in = 0; bool isOK = false; - while (tmppit != end && tmppit->inInset() - // the single '=' is intended below - && (in = tmppit->inInset()->owner())) - { - if (in->lyxCode() == InsetBase::FLOAT_CODE || - in->lyxCode() == InsetBase::WRAP_CODE) { + while (tmppit != end) { + in = pars_[tmppit].inInset(); + // FIXME: in should be always valid. + if (in && + (in->lyxCode() == InsetBase::FLOAT_CODE || + in->lyxCode() == InsetBase::WRAP_CODE)) { isOK = true; break; - } else { + } +#ifdef WITH_WARNINGS +#warning replace this code by something that works +// This code does not work because we have currently no way to move up +// in the hierarchy of insets (JMarc 16/08/2004) +#endif +#if 0 +/* I think this code is supposed to be useful when one has a caption + * in a minipage in a figure inset. We need to go up to be able to see + * that the caption should use "Figure" as label + */ + else { Paragraph const * owner = &ownerPar(buf, in); - tmppit = first_pit; + tmppit = 0; for ( ; tmppit != end; ++tmppit) - if (&*tmppit == owner) + if (&pars_[tmppit] == owner) break; } +#else + ++tmppit; +#endif } if (isOK) { @@ -825,7 +844,7 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit) s = _("Senseless: "); } } - pit->params().labelString(s); + par.params().labelString(s); } } @@ -838,221 +857,52 @@ void LyXText::updateCounters() bv()->buffer()->params().getLyXTextClass().counters().reset(); bool update_pos = false; - - ParagraphList::iterator beg = paragraphs().begin(); - ParagraphList::iterator end = paragraphs().end(); - for (ParagraphList::iterator pit = beg; pit != end; ++pit) { - string const oldLabel = pit->params().labelString(); + + pit_type end = paragraphs().size(); + for (pit_type pit = 0; pit != end; ++pit) { + string const oldLabel = pars_[pit].params().labelString(); size_t maxdepth = 0; - if (pit != beg) - maxdepth = boost::prior(pit)->getMaxDepthAfter(); + if (pit != 0) + maxdepth = pars_[pit - 1].getMaxDepthAfter(); - if (pit->params().depth() > maxdepth) - pit->params().depth(maxdepth); + if (pars_[pit].params().depth() > maxdepth) + pars_[pit].params().depth(maxdepth); // setCounter can potentially change the labelString. setCounter(*bv()->buffer(), pit); - string const & newLabel = pit->params().labelString(); + string const & newLabel = pars_[pit].params().labelString(); if (oldLabel != newLabel) { - redoParagraphInternal(pit); + //lyxerr[Debug::DEBUG] << "changing labels: old: " << oldLabel << " new: " + // << newLabel << endl; update_pos = true; } - } - if (update_pos) - updateParPositions(); } +// this really should just insert the inset and not move the cursor. void LyXText::insertInset(LCursor & cur, InsetBase * inset) { BOOST_ASSERT(this == cur.text()); - recordUndo(cur); - freezeUndo(); + BOOST_ASSERT(inset); cur.paragraph().insertInset(cur.pos(), inset); - // Just to rebreak and refresh correctly. - // The character will not be inserted a second time - insertChar(cur, Paragraph::META_INSET); - // If we enter a highly editable inset the cursor should be before - // the inset. After an undo LyX tries to call inset->edit(...) - // and fails if the cursor is behind the inset and getInset - // does not return the inset! - if (isHighlyEditableInset(inset)) - cursorLeft(cur, true); - unFreezeUndo(); -} - - -void LyXText::cutSelection(LCursor & cur, bool doclear, bool realcut) -{ - BOOST_ASSERT(this == cur.text()); - // Stuff what we got on the clipboard. Even if there is no selection. - - // There is a problem with having the stuffing here in that the - // larger the selection the slower LyX will get. This can be - // solved by running the line below only when the selection has - // finished. The solution used currently just works, to make it - // faster we need to be more clever and probably also have more - // calls to stuffClipboard. (Lgb) - bv()->stuffClipboard(cur.selectionAsString(true)); - - // This doesn't make sense, if there is no selection - if (!cur.selection()) - return; - - // OK, we have a selection. This is always between cur.selBegin() - // and cur.selEnd() - - // make sure that the depth behind the selection are restored, too - recordUndoSelection(cur); - ParagraphList::iterator begpit = getPar(cur.selBegin().par()); - ParagraphList::iterator endpit = getPar(cur.selEnd().par()); - ParagraphList::iterator undopit = undoSpan(endpit); - - int endpos = cur.selEnd().pos(); - - BufferParams const & bufparams = bv()->buffer()->params(); - boost::tie(endpit, endpos) = realcut ? - CutAndPaste::cutSelection(bufparams, - paragraphs(), - begpit, endpit, - cur.selBegin().pos(), endpos, - bufparams.textclass, - doclear) - : CutAndPaste::eraseSelection(bufparams, - paragraphs(), - begpit, endpit, - cur.selBegin().pos(), endpos, - doclear); - // sometimes necessary - if (doclear) - begpit->stripLeadingSpaces(); - - redoParagraphs(begpit, undopit); - // cutSelection can invalidate the cursor so we need to set - // it anew. (Lgb) - // we prefer the end for when tracking changes - cur.pos() = endpos; - cur.par() = parOffset(endpit); - - // need a valid cursor. (Lgb) - cur.clearSelection(); - updateCounters(); -} - - -void LyXText::copySelection(LCursor & cur) -{ - BOOST_ASSERT(this == cur.text()); - // stuff the selection onto the X clipboard, from an explicit copy request - bv()->stuffClipboard(cur.selectionAsString(true)); - - // this doesnt make sense, if there is no selection - if (!cur.selection()) - return; - - // ok we have a selection. This is always between cur.selBegin() - // and sel_end cursor - - // copy behind a space if there is one - while (getPar(cur.selBegin())->size() > cur.selBegin().pos() - && getPar(cur.selBegin())->isLineSeparator(cur.selBegin().pos()) - && (cur.selBegin().par() != cur.selEnd().par() - || cur.selBegin().pos() < cur.selEnd().pos())) - cur.selBegin().pos(cur.selBegin().pos() + 1); - - CutAndPaste::copySelection(getPar(cur.selBegin().par()), - getPar(cur.selEnd().par()), - cur.selBegin().pos(), - cur.selEnd().pos(), - bv()->buffer()->params().textclass); -} - - -void LyXText::pasteSelection(LCursor & cur, size_t sel_index) -{ - // this does not make sense, if there is nothing to paste - if (!CutAndPaste::checkPastePossible()) - return; - - recordUndo(cur); - - ParagraphList::iterator endpit; - PitPosPair ppp; - - ErrorList el; - - boost::tie(ppp, endpit) = - CutAndPaste::pasteSelection(*bv()->buffer(), - paragraphs(), - getPar(cur.par()), cur.pos(), - bv()->buffer()->params().textclass, - sel_index, el); - bufferErrors(*bv()->buffer(), el); - bv()->showErrorList(_("Paste")); - - redoParagraphs(getPar(cur.par()), endpit); - - cur.clearSelection(); - cur.resetAnchor(); - setCursor(cur, parOffset(ppp.first), ppp.second); - cur.setSelection(); - updateCounters(); -} - - -void LyXText::setSelectionRange(LCursor & cur, lyx::pos_type length) -{ - if (!length) - return; - cur.resetAnchor(); - while (length--) - cursorRight(cur, true); - cur.setSelection(); -} - - -// simple replacing. The font of the first selected character is used -void LyXText::replaceSelectionWithString(LCursor & cur, string const & str) -{ - recordUndo(cur); - freezeUndo(); - - // Get font setting before we cut - pos_type pos = cur.selEnd().pos(); - LyXFont const font = getPar(cur.selBegin()) - ->getFontSettings(bv()->buffer()->params(), - cur.selBegin().pos()); - - // Insert the new string - string::const_iterator cit = str.begin(); - string::const_iterator end = str.end(); - for (; cit != end; ++cit) { - getPar(cur.selEnd())->insertChar(pos, (*cit), font); - ++pos; - } - - // Cut the selection - cutSelection(cur, true, false); - unFreezeUndo(); } // needed to insert the selection void LyXText::insertStringAsLines(LCursor & cur, string const & str) { - ParagraphList::iterator pit = getPar(cur.par()); - ParagraphList::iterator endpit = boost::next(pit); - pos_type pos = cursor().pos(); + pit_type pit = cur.pit(); + pos_type pos = cur.pos(); recordUndo(cur); // only to be sure, should not be neccessary cur.clearSelection(); - bv()->buffer()->insertStringAsLines(pit, pos, current_font, str); + cur.buffer().insertStringAsLines(pars_, pit, pos, current_font, str, + autoBreakRows_); - redoParagraphs(getPar(cur.par()), endpit); cur.resetAnchor(); - setCursor(cur, cur.par(), pos); + setCursor(cur, cur.pit(), pos); cur.setSelection(); } @@ -1084,70 +934,46 @@ void LyXText::insertStringAsParagraphs(LCursor & cur, string const & str) } -bool LyXText::setCursor(LCursor & cur, par_type par, pos_type pos, +bool LyXText::setCursor(LCursor & cur, pit_type par, pos_type pos, bool setfont, bool boundary) { - CursorSlice old_cursor = cur.current(); + LCursor old = cur; setCursorIntern(cur, par, pos, setfont, boundary); - return deleteEmptyParagraphMechanism(cur.current(), old_cursor); + return deleteEmptyParagraphMechanism(cur, old); } -void LyXText::setCursor(CursorSlice & cur, par_type par, +void LyXText::setCursor(CursorSlice & cur, pit_type par, pos_type pos, bool boundary) { BOOST_ASSERT(par != int(paragraphs().size())); - - cur.par(par); - cur.pos(pos); - cur.boundary(boundary); - - // no rows, no fun... - if (paragraphs().begin()->rows.empty()) - return; + cur.pit() = par; + cur.pos() = pos; + cur.boundary() = boundary; // now some strict checking - Paragraph & para = *getPar(par); - Row const & row = *para.getRow(pos); - pos_type const end = row.endpos(); + Paragraph & para = getPar(par); // None of these should happen, but we're scaredy-cats if (pos < 0) { lyxerr << "dont like -1" << endl; - pos = 0; - cur.pos(0); BOOST_ASSERT(false); - } else if (pos > para.size()) { + } + + if (pos > para.size()) { lyxerr << "dont like 1, pos: " << pos << " size: " << para.size() - << " row.pos():" << row.pos() << " par: " << par << endl; - pos = 0; - cur.pos(0); - BOOST_ASSERT(false); - } else if (pos > end) { - lyxerr << "dont like 2 please report" << endl; - // This shouldn't happen. - pos = end; - cur.pos(pos); - BOOST_ASSERT(false); - } else if (pos < row.pos()) { - lyxerr << "dont like 3 please report pos:" << pos - << " size: " << para.size() - << " row.pos():" << row.pos() - << " par: " << par << endl; - pos = row.pos(); - cur.pos(pos); BOOST_ASSERT(false); } } void LyXText::setCursorIntern(LCursor & cur, - par_type par, pos_type pos, bool setfont, bool boundary) + pit_type par, pos_type pos, bool setfont, bool boundary) { - setCursor(cur.current(), par, pos, boundary); - cur.x_target() = cursorX(cur.current()); + setCursor(cur.top(), par, pos, boundary); + cur.setTargetX(); if (setfont) setCurrentFont(cur); } @@ -1157,7 +983,7 @@ void LyXText::setCurrentFont(LCursor & cur) { BOOST_ASSERT(this == cur.text()); pos_type pos = cur.pos(); - ParagraphList::iterator pit = getPar(cur.par()); + Paragraph & par = cur.paragraph(); if (cur.boundary() && pos > 0) --pos; @@ -1166,7 +992,7 @@ void LyXText::setCurrentFont(LCursor & cur) if (pos == cur.lastpos()) --pos; else // potentional bug... BUG (Lgb) - if (pit->isSeparator(pos)) { + if (par.isSeparator(pos)) { if (pos > cur.textRow().pos() && bidi.level(pos) % 2 == bidi.level(pos - 1) % 2) @@ -1176,14 +1002,14 @@ void LyXText::setCurrentFont(LCursor & cur) } } - BufferParams const & bufparams = bv()->buffer()->params(); - current_font = pit->getFontSettings(bufparams, pos); - real_current_font = getFont(pit, pos); + BufferParams const & bufparams = cur.buffer().params(); + current_font = par.getFontSettings(bufparams, pos); + real_current_font = getFont(par, pos); if (cur.pos() == cur.lastpos() - && bidi.isBoundary(*bv()->buffer(), *pit, cur.pos()) + && bidi.isBoundary(cur.buffer(), par, cur.pos()) && !cur.boundary()) { - Language const * lang = pit->getParLanguage(bufparams); + Language const * lang = par.getParLanguage(bufparams); current_font.setLanguage(lang); current_font.setNumber(LyXFont::OFF); real_current_font.setLanguage(lang); @@ -1195,32 +1021,33 @@ void LyXText::setCurrentFont(LCursor & cur) // x is an absolute screen coord // returns the column near the specified x-coordinate of the row // x is set to the real beginning of this column -pos_type LyXText::getColumnNearX(ParagraphList::iterator pit, +pos_type LyXText::getColumnNearX(pit_type const pit, Row const & row, int & x, bool & boundary) const { - x -= xo_; - double tmpx = row.x(); - double fill_separator = row.fill_separator(); - double fill_hfill = row.fill_hfill(); - double fill_label_hfill = row.fill_label_hfill(); + int const xo = theCoords.get(this, pit).x_; + x -= xo; + RowMetrics const r = computeRowMetrics(pit, row); + Paragraph const & par = pars_[pit]; pos_type vc = row.pos(); pos_type end = row.endpos(); pos_type c = 0; - LyXLayout_ptr const & layout = pit->layout(); + LyXLayout_ptr const & layout = par.layout(); bool left_side = false; - pos_type body_pos = pit->beginOfBody(); + pos_type body_pos = par.beginOfBody(); + + double tmpx = r.x; double last_tmpx = tmpx; if (body_pos > 0 && - (body_pos > end || !pit->isLineSeparator(body_pos - 1))) + (body_pos > end || !par.isLineSeparator(body_pos - 1))) body_pos = 0; // check for empty row if (vc == end) { - x = int(tmpx) + xo_; + x = int(tmpx) + xo; return 0; } @@ -1228,24 +1055,24 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit, c = bidi.vis2log(vc); last_tmpx = tmpx; if (body_pos > 0 && c == body_pos - 1) { - tmpx += fill_label_hfill + - font_metrics::width(layout->labelsep, getLabelFont(pit)); - if (pit->isLineSeparator(body_pos - 1)) - tmpx -= singleWidth(pit, body_pos - 1); + tmpx += r.label_hfill + + font_metrics::width(layout->labelsep, getLabelFont(par)); + if (par.isLineSeparator(body_pos - 1)) + tmpx -= singleWidth(par, body_pos - 1); } - if (hfillExpansion(*pit, row, c)) { - tmpx += singleWidth(pit, c); + if (hfillExpansion(par, row, c)) { + tmpx += singleWidth(par, c); if (c >= body_pos) - tmpx += fill_hfill; + tmpx += r.hfill; else - tmpx += fill_label_hfill; - } else if (pit->isSeparator(c)) { - tmpx += singleWidth(pit, c); + tmpx += r.label_hfill; + } else if (par.isSeparator(c)) { + tmpx += singleWidth(par, c); if (c >= body_pos) - tmpx += fill_separator; + tmpx += r.separator; } else { - tmpx += singleWidth(pit, c); + tmpx += singleWidth(par, c); } ++vc; } @@ -1260,13 +1087,11 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit, boundary = false; // This (rtl_support test) is not needed, but gives // some speedup if rtl_support == false - bool const lastrow = lyxrc.rtl_support && row.endpos() == pit->size(); + bool const lastrow = lyxrc.rtl_support && row.endpos() == par.size(); // If lastrow is false, we don't need to compute // the value of rtl. - bool const rtl = lastrow - ? pit->isRightToLeftPar(bv()->buffer()->params()) - : false; + bool const rtl = lastrow ? isRTL(par) : false; if (lastrow && ((rtl && left_side && vc == row.pos() && x < tmpx - 5) || (!rtl && !left_side && vc == end && x > tmpx + 5))) @@ -1280,72 +1105,110 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit, bool const rtl = (bidi.level(c) % 2 == 1); if (left_side == rtl) { ++c; - boundary = bidi.isBoundary(*bv()->buffer(), *pit, c); + boundary = bidi.isBoundary(*bv()->buffer(), par, c); } } - if (row.pos() < end && c >= end && pit->isNewline(end - 1)) { + if (row.pos() < end && c >= end && par.isNewline(end - 1)) { if (bidi.level(end -1) % 2 == 0) - tmpx -= singleWidth(pit, end - 1); + tmpx -= singleWidth(par, end - 1); else - tmpx += singleWidth(pit, end - 1); + tmpx += singleWidth(par, end - 1); c = end - 1; } - x = int(tmpx) + xo_; + x = int(tmpx) + xo; return c - row.pos(); } -// x,y are coordinates relative to this LyXText -void LyXText::setCursorFromCoordinates(LCursor & cur, int x, int y) +// y is screen coordinate +pit_type LyXText::getPitNearY(int y) const { - CursorSlice old_cursor = cur.current(); - ParagraphList::iterator pit; - Row const & row = *getRowNearY(y, pit); - lyxerr << "hit row at: " << row.pos() << endl; - bool bound = false; - int xx = x + xo_; // getRowNearX get absolute x coords - pos_type const pos = row.pos() + getColumnNearX(pit, row, xx, bound); - cur.par() = parOffset(pit); - cur.pos() = pos; - cur.boundary() = bound; - deleteEmptyParagraphMechanism(cur.current(), old_cursor); + BOOST_ASSERT(!paragraphs().empty()); + BOOST_ASSERT(theCoords.getParPos().find(this) != theCoords.getParPos().end()); + CoordCache::InnerParPosCache const & cc = theCoords.getParPos().find(this)->second; + lyxerr << "LyXText::getPitNearY: y: " << y << " cache size: " + << cc.size() << endl; + + // look for highest numbered paragraph with y coordinate less than given y + pit_type pit = 0; + int yy = -1; + CoordCache::InnerParPosCache::const_iterator it = cc.begin(); + CoordCache::InnerParPosCache::const_iterator et = cc.end(); + for (; it != et; ++it) { + lyxerr << " examining: pit: " << it->first << " y: " + << it->second.y_ << endl; + if (it->first >= pit && int(it->second.y_) - int(pars_[it->first].ascent()) <= y) { + pit = it->first; + yy = it->second.y_; + } + } + + lyxerr << " found best y: " << yy << " for pit: " << pit << endl; + return pit; +} + + +Row const & LyXText::getRowNearY(int y, pit_type pit) const +{ + Paragraph const & par = pars_[pit]; + int yy = theCoords.get(this, pit).y_ - par.ascent(); + BOOST_ASSERT(!par.rows().empty()); + RowList::const_iterator rit = par.rows().begin(); + RowList::const_iterator const rlast = boost::prior(par.rows().end()); + for (; rit != rlast; yy += rit->height(), ++rit) + if (yy + rit->height() > y) + break; + return *rit; } // x,y are absolute screen coordinates -InsetBase * LyXText::editXY(LCursor & cur, int x, int y) +// sets cursor recursively descending into nested editable insets +InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const { - ParagraphList::iterator pit; - Row const & row = *getRowNearY(y - yo_, pit); + pit_type pit = getPitNearY(y); + BOOST_ASSERT(pit != -1); + Row const & row = getRowNearY(y, pit); bool bound = false; int xx = x; // is modified by getColumnNearX pos_type const pos = row.pos() + getColumnNearX(pit, row, xx, bound); - cur.par() = parOffset(pit); + cur.pit() = pit; cur.pos() = pos; cur.boundary() = bound; + cur.x_target() = x; // try to descend into nested insets InsetBase * inset = checkInsetHit(x, y); - if (!inset) + lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl; + if (!inset) { + // Either we deconst editXY or better we move current_font + // and real_current_font to LCursor + const_cast(this)->setCurrentFont(cur); return 0; + } // This should be just before or just behind the // cursor position set above. - BOOST_ASSERT((pos != 0 && inset == pit->getInset(pos - 1)) - || inset == pit->getInset(pos)); + BOOST_ASSERT((pos != 0 && inset == pars_[pit].getInset(pos - 1)) + || inset == pars_[pit].getInset(pos)); // Make sure the cursor points to the position before // this inset. - if (inset == pit->getInset(pos - 1)) + if (inset == pars_[pit].getInset(pos - 1)) --cur.pos(); - return inset->editXY(cur, x, y); + inset = inset->editXY(cur, x, y); + if (cur.top().text() == this) + const_cast(this)->setCurrentFont(cur); + return inset; } bool LyXText::checkAndActivateInset(LCursor & cur, bool front) { + if (cur.selection()) + return false; if (cur.pos() == cur.lastpos()) return false; InsetBase * inset = cur.nextInset(); @@ -1356,162 +1219,155 @@ bool LyXText::checkAndActivateInset(LCursor & cur, bool front) } -DispatchResult LyXText::moveRight(LCursor & cur) +bool LyXText::cursorLeft(LCursor & cur) { - if (rtl(cur)) - return moveLeftIntern(cur, false, true, false); - else - return moveRightIntern(cur, true, true, false); -} - + if (cur.pos() != 0) { + bool boundary = cur.boundary(); + bool updateNeeded = setCursor(cur, cur.pit(), cur.pos() - 1, true, false); + if (!checkAndActivateInset(cur, false)) { + if (false && !boundary && + bidi.isBoundary(cur.buffer(), cur.paragraph(), cur.pos() + 1)) + updateNeeded |= + setCursor(cur, cur.pit(), cur.pos() + 1, true, true); + } + return updateNeeded; + } -DispatchResult LyXText::moveLeft(LCursor & cur) -{ - if (rtl(cur)) - return moveRightIntern(cur, true, true, false); - else - return moveLeftIntern(cur, false, true, false); + if (cur.pit() != 0) { + // Steps into the paragraph above + return setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size()); + } + return false; } -DispatchResult LyXText::moveRightIntern(LCursor & cur, - bool front, bool activate_inset, bool selecting) +bool LyXText::cursorRight(LCursor & cur) { - if (cur.par() == cur.lastpar() && cur.pos() == cur.lastpos()) - return DispatchResult(false, FINISHED_RIGHT); - if (activate_inset && checkAndActivateInset(cur, front)) - return DispatchResult(true, true); - cursorRight(cur, true); - if (!selecting) - cur.clearSelection(); - return DispatchResult(true); -} + if (false && cur.boundary()) { + return setCursor(cur, cur.pit(), cur.pos(), true, false); + } + if (cur.pos() != cur.lastpos()) { + bool updateNeeded = false; + if (!checkAndActivateInset(cur, true)) { + updateNeeded |= setCursor(cur, cur.pit(), cur.pos() + 1, true, false); + if (false && bidi.isBoundary(cur.buffer(), cur.paragraph(), + cur.pos())) + updateNeeded |= setCursor(cur, cur.pit(), cur.pos(), true, true); + } + return updateNeeded; + } -DispatchResult LyXText::moveLeftIntern(LCursor & cur, - bool front, bool activate_inset, bool selecting) -{ - if (cur.par() == 0 && cur.pos() == 0) - return DispatchResult(false, FINISHED); - cursorLeft(cur, true); - if (!selecting) - cur.clearSelection(); - if (activate_inset && checkAndActivateInset(cur, front)) - return DispatchResult(true, true); - return DispatchResult(true); + if (cur.pit() != cur.lastpit()) + return setCursor(cur, cur.pit() + 1, 0); + return false; } -DispatchResult LyXText::moveUp(LCursor & cur) +bool LyXText::cursorUp(LCursor & cur) { - if (cur.par() == 0 && cur.crow() == 0) - return DispatchResult(false, FINISHED_UP); - cursorUp(cur, false); - cur.clearSelection(); - return DispatchResult(true); -} + Paragraph const & par = cur.paragraph(); + int const row = par.pos2row(cur.pos()); + int const x = cur.targetX(); + if (!cur.selection()) { + int const y = bv_funcs::getPos(cur).y_; + LCursor old = cur; + editXY(cur, x, y - par.rows()[row].ascent() - 1); + + // This happens when you move out of an inset. + // And to give the DEPM the possibility of doing + // something we must provide it with two different + // cursors. (Lgb) + LCursor dummy = cur; + if (dummy == old) + ++dummy.pos(); + + return deleteEmptyParagraphMechanism(dummy, old); + } -DispatchResult LyXText::moveDown(LCursor & cur) -{ - if (cur.par() == cur.lastpar() && cur.textRow().endpos() == cur.lastpos()) - return DispatchResult(false, FINISHED_DOWN); - cursorDown(cur, false); - cur.clearSelection(); - return DispatchResult(true); -} - + bool updateNeeded = false; -bool LyXText::cursorLeft(LCursor & cur, bool internal) -{ - if (cur.pos() != 0) { - bool boundary = cur.boundary(); - setCursor(cur, cur.par(), cur.pos() - 1, true, false); - if (!internal && !boundary && - bidi.isBoundary(*bv()->buffer(), cur.paragraph(), cur.pos() + 1)) - setCursor(cur, cur.par(), cur.pos() + 1, true, true); - return true; + if (row > 0) { + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), row - 1, x)); + } else if (cur.pit() > 0) { + --cur.pit(); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), par.rows().size() - 1, x)); } - if (cur.par() != 0) { - // steps into the paragraph above - setCursor(cur, cur.par() - 1, getPar(cur.par() - 1)->size()); - return true; - } + cur.x_target() = x; - return false; + return updateNeeded; } -bool LyXText::cursorRight(LCursor & cur, bool internal) +bool LyXText::cursorDown(LCursor & cur) { - if (!internal && cur.boundary()) { - setCursor(cur, cur.par(), cur.pos(), true, false); - return true; - } + Paragraph const & par = cur.paragraph(); + int const row = par.pos2row(cur.pos()); + int const x = cur.targetX(); - if (cur.pos() != cur.lastpos()) { - setCursor(cur, cur.par(), cur.pos() + 1, true, false); - if (!internal && bidi.isBoundary(*bv()->buffer(), cur.paragraph(), - cur.pos())) - setCursor(cur, cur.par(), cur.pos(), true, true); - return true; - } + if (!cur.selection()) { + int const y = bv_funcs::getPos(cur).y_; + LCursor old = cur; + editXY(cur, x, y + par.rows()[row].descent() + 1); - if (cur.par() != cur.lastpar()) { - setCursor(cur, cur.par() + 1, 0); - return true; - } + // This happens when you move out of an inset. + // And to give the DEPM the possibility of doing + // something we must provide it with two different + // cursors. (Lgb) + LCursor dummy = cur; + if (dummy == old) + ++dummy.pos(); - return false; -} + bool const changed = deleteEmptyParagraphMechanism(dummy, old); + // Make sure that cur gets back whatever happened to dummy(Lgb) + if (changed) + cur = dummy; + + return changed; -void LyXText::cursorUp(LCursor & cur, bool selecting) -{ - Row const & row = cur.textRow(); - int x = cur.x_target(); - int y = cursorY(cur.current()) - row.baseline() - 1; - setCursorFromCoordinates(cur, x - xo_, y - yo_); - - if (!selecting) { - InsetBase * inset_hit = checkInsetHit(cur.x_target(), y); - if (inset_hit && isHighlyEditableInset(inset_hit)) - inset_hit->editXY(cur, cur.x_target(), y); } -} + bool updateNeeded = false; -void LyXText::cursorDown(LCursor & cur, bool selecting) -{ - Row const & row = cur.textRow(); - int x = cur.x_target(); - int y = cursorY(cur.current()) - row.baseline() + row.height() + 1; - setCursorFromCoordinates(cur, x - xo_, y - yo_); - - if (!selecting) { - InsetBase * inset_hit = checkInsetHit(cur.x_target(), y); - if (inset_hit && isHighlyEditableInset(inset_hit)) - inset_hit->editXY(cur, cur.x_target(), y); + if (row + 1 < int(par.rows().size())) { + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), row + 1, x)); + } else if (cur.pit() + 1 < int(paragraphs().size())) { + ++cur.pit(); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), 0, x)); } + + cur.x_target() = x; + + return updateNeeded; } -void LyXText::cursorUpParagraph(LCursor & cur) +bool LyXText::cursorUpParagraph(LCursor & cur) { + bool updated = false; if (cur.pos() > 0) - setCursor(cur, cur.par(), 0); - else if (cur.par() != 0) - setCursor(cur, cur.par() - 1, 0); + updated = setCursor(cur, cur.pit(), 0); + else if (cur.pit() != 0) + updated = setCursor(cur, cur.pit() - 1, 0); + return updated; } -void LyXText::cursorDownParagraph(LCursor & cur) +bool LyXText::cursorDownParagraph(LCursor & cur) { - if (cur.par() != cur.lastpar()) - setCursor(cur, cur.par() + 1, 0); + bool updated = false; + if (cur.pit() != cur.lastpit()) + updated = setCursor(cur, cur.pit() + 1, 0); else - setCursor(cur, cur.par(), cur.lastpos()); + updated = setCursor(cur, cur.pit(), cur.lastpos()); + return updated; } @@ -1519,36 +1375,33 @@ void LyXText::cursorDownParagraph(LCursor & cur) // position. Called by deleteEmptyParagraphMechanism void LyXText::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where) { - // do notheing if cursor is not in the paragraph where the + // Do nothing if cursor is not in the paragraph where the // deletion occured, - if (cur.par() != where.par()) + if (cur.pit() != where.pit()) return; - // if cursor position is after the deletion place update it + // If cursor position is after the deletion place update it if (cur.pos() > where.pos()) --cur.pos(); - // check also if we don't want to set the cursor on a spot behind the + // Check also if we don't want to set the cursor on a spot behind the // pagragraph because we erased the last character. if (cur.pos() > cur.lastpos()) cur.pos() = cur.lastpos(); } -bool LyXText::deleteEmptyParagraphMechanism(CursorSlice & cur, - CursorSlice const & old_cursor) +bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) { -#warning Disabled as it crashes after the cursor data shift... (Andre) - return false; - // Would be wrong to delete anything if we have a selection. - //if (cur.selection()) - // return false; + if (cur.selection()) + return false; + + //lyxerr[Debug::DEBUG] << "DEPM: cur:\n" << cur << "old:\n" << old << endl; + Paragraph const & oldpar = pars_[old.pit()]; -#if 0 // We allow all kinds of "mumbo-jumbo" when freespacing. - ParagraphList::iterator const old_pit = getPar(old_cursor.par()); - if (old_pit->isFreeSpacing()) + if (oldpar.isFreeSpacing()) return false; /* Ok I'll put some comments here about what is missing. @@ -1566,145 +1419,114 @@ bool LyXText::deleteEmptyParagraphMechanism(CursorSlice & cur, that I can get some feedback. (Lgb) */ - // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator + // If old.pos() == 0 and old.pos()(1) == LineSeparator // delete the LineSeparator. // MISSING - // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator + // If old.pos() == 1 and old.pos()(0) == LineSeparator // delete the LineSeparator. // MISSING - // If the pos around the old_cursor were spaces, delete one of them. - if (old_cursor.par() != cur.par() || old_cursor.pos() != cur.pos()) { + // If the chars around the old cursor were spaces, delete one of them. + if (old.pit() != cur.pit() || old.pos() != cur.pos()) { - // Only if the cursor has really moved - if (old_cursor.pos() > 0 - && old_cursor.pos() < old_pit->size() - && old_pit->isLineSeparator(old_cursor.pos()) - && old_pit->isLineSeparator(old_cursor.pos() - 1)) { - bool erased = old_pit->erase(old_cursor.pos() - 1); - redoParagraph(old_pit); - - if (!erased) - return false; + // Only if the cursor has really moved. + if (old.pos() > 0 + && old.pos() < oldpar.size() + && oldpar.isLineSeparator(old.pos()) + && oldpar.isLineSeparator(old.pos() - 1)) { + pars_[old.pit()].erase(old.pos() - 1); #ifdef WITH_WARNINGS #warning This will not work anymore when we have multiple views of the same buffer // In this case, we will have to correct also the cursors held by // other bufferviews. It will probably be easier to do that in a more // automated way in CursorSlice code. (JMarc 26/09/2001) #endif - // correct all cursors held by the LyXText - fixCursorAfterDelete(cursor(), old_cursor); - fixCursorAfterDelete(anchor(), old_cursor); - return false; + // correct all cursor parts + fixCursorAfterDelete(cur.top(), old.top()); +#ifdef WITH_WARNINGS +#warning DEPM, look here +#endif + //fixCursorAfterDelete(cur.anchor(), old.top()); + return true; } } - // don't delete anything if this is the ONLY paragraph! - if (paragraphs().size() == 1) + // only do our magic if we changed paragraph + if (old.pit() == cur.pit()) return false; - // Do not delete empty paragraphs with keepempty set. - if (old_pit->allowEmpty()) + // don't delete anything if this is the ONLY paragraph! + if (pars_.size() == 1) return false; - // only do our magic if we changed paragraph - if (old_cursor.par() == cur.par()) + // Do not delete empty paragraphs with keepempty set. + if (oldpar.allowEmpty()) return false; // record if we have deleted a paragraph // we can't possibly have deleted a paragraph before this point bool deleted = false; - if (old_pit->empty() - || (old_pit->size() == 1 && old_pit->isLineSeparator(0))) { + if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) { // ok, we will delete something - CursorSlice tmpcursor; - deleted = true; bool selection_position_was_oldcursor_position = - anchor().par() == old_cursor.par() - && anchor().pos() == old_cursor.pos(); - - tmpcursor = cursor(); - cursor() = old_cursor; // that undo can restore the right cursor position + cur.anchor().pit() == old.pit() && cur.anchor().pos() == old.pos(); - ParagraphList::iterator endpit = boost::next(old_pit); - while (endpit != paragraphs().end() && endpit->getDepth()) - ++endpit; + // This is a bit of a overkill. We change the old and the cur par + // at max, certainly not everything in between... + recUndo(old.pit(), cur.pit()); - recUndo(parOffset(old_pit), parOffset(endpit) - 1); - cursor() = tmpcursor; + // Delete old par. + pars_.erase(pars_.begin() + old.pit()); - // delete old par - paragraphs().erase(old_pit); - // update cursor par offset - --cur.par(); - redoParagraph(); + // Update cursor par offset if necessary. + // Some 'iterator registration' would be nice that takes care of + // such events. Maybe even signal/slot? + if (cur.pit() > old.pit()) + --cur.pit(); +#ifdef WITH_WARNINGS +#warning DEPM, look here +#endif +// if (cur.anchor().pit() > old.pit()) +// --cur.anchor().pit(); if (selection_position_was_oldcursor_position) { // correct selection - bv()->resetAnchor(); + cur.resetAnchor(); } } if (deleted) return true; - if (old_pit->stripLeadingSpaces()) { - redoParagraph(old_pit); - bv()->resetAnchor(); - } + if (pars_[old.pit()].stripLeadingSpaces()) + cur.resetAnchor(); + return false; -#endif } ParagraphList & LyXText::paragraphs() const { - return const_cast(paragraphs_); + return const_cast(pars_); } -void LyXText::recUndo(par_type first, par_type last) const +void LyXText::recUndo(pit_type first, pit_type last) const { recordUndo(bv()->cursor(), Undo::ATOMIC, first, last); } -void LyXText::recUndo(par_type par) const +void LyXText::recUndo(pit_type par) const { recordUndo(bv()->cursor(), Undo::ATOMIC, par, par); } -bool LyXText::isInInset() const -{ - return in_inset_; -} - - -bool LyXText::toggleInset(LCursor & cur) -{ - InsetBase * inset = cur.nextInset(); - // is there an editable inset at cursor position? - if (!isEditableInset(inset)) - return false; - cur.message(inset->editMessage()); - - // do we want to keep this?? (JMarc) - if (!isHighlyEditableInset(inset)) - recordUndo(cur); - - if (inset->isOpen()) - inset->close(); - else - inset->open(); - return true; -} - - int defaultRowHeight() { return int(font_metrics::maxHeight(LyXFont(LyXFont::ALL_SANE)) * 1.2);