X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext2.C;h=917808ec8395ef3fa0de90f9adcdbae024957eaf;hb=ee1163d8e8cbe814912f3498f42fa65a55f22bb7;hp=129ac6aa1276fda0a8e42233b39fb3756961d121;hpb=d194cfffa5f68f425cff20770956f81c74cf9d0f;p=lyx.git diff --git a/src/text2.C b/src/text2.C index 129ac6aa12..917808ec83 100644 --- a/src/text2.C +++ b/src/text2.C @@ -26,15 +26,12 @@ #include "bufferparams.h" #include "BufferView.h" #include "Bullet.h" -#include "counters.h" #include "coordcache.h" #include "cursor.h" #include "CutAndPaste.h" #include "debug.h" #include "dispatchresult.h" #include "errorlist.h" -#include "Floating.h" -#include "FloatList.h" #include "funcrequest.h" #include "gettext.h" #include "language.h" @@ -45,26 +42,21 @@ #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "pariterator.h" #include "undo.h" #include "vspace.h" #include "frontends/font_metrics.h" #include "frontends/LyXView.h" -#include "insets/insetbibitem.h" #include "insets/insetenv.h" -#include "insets/insetfloat.h" -#include "insets/insetwrap.h" -#include "support/lstrings.h" #include "support/textutils.h" -#include "support/tostr.h" #include -using lyx::par_type; +using lyx::pit_type; using lyx::pos_type; -using lyx::support::bformat; using std::endl; using std::ostringstream; @@ -72,9 +64,10 @@ using std::string; LyXText::LyXText(BufferView * bv) - : width_(0), maxwidth_(bv ? bv->workWidth() : 100), height_(0), + : maxwidth_(bv ? bv->workWidth() : 100), background_color_(LColor::background), - bv_owner(bv), xo_(0), yo_(0) + bv_owner(bv), + autoBreakRows_(false) {} @@ -83,16 +76,16 @@ void LyXText::init(BufferView * bv) BOOST_ASSERT(bv); bv_owner = bv; maxwidth_ = bv->workWidth(); - width_ = maxwidth_; - height_ = 0; + dim_.wid = maxwidth_; + dim_.asc = 10; + dim_.des = 10; - par_type const end = paragraphs().size(); - for (par_type pit = 0; pit != end; ++pit) - pars_[pit].rows.clear(); + pit_type const end = paragraphs().size(); + for (pit_type pit = 0; pit != end; ++pit) + pars_[pit].rows().clear(); current_font = getFont(pars_[0], 0); - redoParagraphs(0, end); - updateCounters(); + updateCounters(*bv->buffer()); } @@ -102,40 +95,35 @@ bool LyXText::isMainText() const } -// takes absolute x,y coordinates -InsetBase * LyXText::checkInsetHit(int x, int y) const +//takes screen x,y coordinates +InsetBase * LyXText::checkInsetHit(int x, int y) const { - par_type pit; - par_type end; + pit_type pit = getPitNearY(y); + BOOST_ASSERT(pit != -1); - getParsInRange(paragraphs(), - bv()->top_y() - yo_, - bv()->top_y() - yo_ + bv()->workHeight(), - pit, end); + Paragraph const & par = pars_[pit]; - // convert to screen-absolute y coordinate - y -= bv()->top_y(); lyxerr << "checkInsetHit: x: " << x << " y: " << y << endl; - lyxerr << " pit: " << pit << " end: " << end << endl; - for (; pit != end; ++pit) { - InsetList::const_iterator iit = pars_[pit].insetlist.begin(); - InsetList::const_iterator iend = pars_[pit].insetlist.end(); - for (; iit != iend; ++iit) { - InsetBase * inset = iit->inset; + 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.insets_.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"; + 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; - } + if (inset->covers(x, y)) { + lyxerr << "Hit inset: " << inset << endl; + return inset; } } lyxerr << "No inset hit. " << endl; @@ -191,7 +179,7 @@ LyXFont LyXText::getFont(Paragraph const & par, pos_type const pos) const } -LyXFont LyXText::getLayoutFont(par_type const pit) const +LyXFont LyXText::getLayoutFont(pit_type const pit) const { LyXLayout_ptr const & layout = pars_[pit].layout(); @@ -222,7 +210,7 @@ LyXFont LyXText::getLabelFont(Paragraph const & par) const } -void LyXText::setCharFont(par_type 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 = pars_[pit].layout(); @@ -237,12 +225,12 @@ void LyXText::setCharFont(par_type pit, pos_type pos, LyXFont const & fnt) // Realize against environment font information if (pars_[pit].getDepth()) { - par_type tp = pit; + pit_type tp = pit; while (!layoutfont.resolved() && - tp != par_type(paragraphs().size()) && + tp != pit_type(paragraphs().size()) && pars_[tp].getDepth()) { tp = outerHook(tp, paragraphs()); - if (tp != par_type(paragraphs().size())) + if (tp != pit_type(paragraphs().size())) layoutfont.realize(pars_[tp].layout()->font); } } @@ -279,10 +267,10 @@ void LyXText::makeFontEntriesLayoutSpecific(BufferParams const & params, // return past-the-last paragraph influenced by a layout change on pit -par_type LyXText::undoSpan(par_type pit) +pit_type LyXText::undoSpan(pit_type pit) { - par_type end = paragraphs().size(); - par_type nextpit = pit + 1; + pit_type end = paragraphs().size(); + pit_type nextpit = pit + 1; if (nextpit == end) return nextpit; //because of parindents @@ -297,16 +285,16 @@ par_type LyXText::undoSpan(par_type pit) } -par_type LyXText::setLayout(par_type start, par_type end, string const & layout) +pit_type LyXText::setLayout(pit_type start, pit_type end, string const & layout) { BOOST_ASSERT(start != end); - par_type undopit = undoSpan(end - 1); + pit_type undopit = undoSpan(end - 1); recUndo(start, undopit - 1); BufferParams const & bufparams = bv()->buffer()->params(); LyXLayout_ptr const & lyxlayout = bufparams.getLyXTextClass()[layout]; - for (par_type pit = start; pit != end; ++pit) { + for (pit_type pit = start; pit != end; ++pit) { pars_[pit].applyLayout(lyxlayout); makeFontEntriesLayoutSpecific(bufparams, pars_[pit]); if (lyxlayout->margintype == MARGIN_MANUAL) @@ -338,29 +326,16 @@ void LyXText::setLayout(LCursor & cur, string const & layout) return; } - par_type start = cur.selBegin().par(); - par_type end = cur.selEnd().par() + 1; - par_type endpit = setLayout(start, end, layout); - redoParagraphs(start, endpit); - updateCounters(); + pit_type start = cur.selBegin().pit(); + pit_type end = cur.selEnd().pit() + 1; + setLayout(start, end, layout); + updateCounters(cur.buffer()); } namespace { -void getSelectionSpan(LCursor & cur, par_type & beg, par_type & end) -{ - if (!cur.selection()) { - beg = cur.par(); - end = cur.par() + 1; - } else { - beg = cur.selBegin().par(); - end = cur.selEnd().par() + 1; - } -} - - bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, Paragraph const & par, int max_depth) { @@ -381,13 +356,11 @@ bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const { BOOST_ASSERT(this == cur.text()); - par_type beg, end; - getSelectionSpan(cur, beg, end); - int max_depth = 0; - if (beg != 0) - max_depth = pars_[beg - 1].getMaxDepthAfter(); + 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 (par_type pit = beg; pit != end; ++pit) { + for (pit_type pit = beg; pit != end; ++pit) { if (::changeDepthAllowed(type, pars_[pit], max_depth)) return true; max_depth = pars_[pit].getMaxDepthAfter(); @@ -399,27 +372,25 @@ bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const void LyXText::changeDepth(LCursor & cur, DEPTH_CHANGE type) { BOOST_ASSERT(this == cur.text()); - par_type beg, end; - getSelectionSpan(cur, beg, end); + pit_type const beg = cur.selBegin().pit(); + pit_type const end = cur.selEnd().pit() + 1; recordUndoSelection(cur); + int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0); - int max_depth = 0; - if (beg != 0) - max_depth = pars_[beg - 1].getMaxDepthAfter(); - - for (par_type pit = beg; pit != end; ++pit) { - if (::changeDepthAllowed(type, pars_[pit], max_depth)) { - int const depth = pars_[pit].params().depth(); + 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) - pars_[pit].params().depth(depth + 1); + par.params().depth(depth + 1); else - pars_[pit].params().depth(depth - 1); + par.params().depth(depth - 1); } - max_depth = pars_[pit].getMaxDepthAfter(); + max_depth = par.getMaxDepthAfter(); } // this handles the counter labels, and also fixes up // depth values for follow-on (child) paragraphs - updateCounters(); + updateCounters(cur.buffer()); } @@ -431,7 +402,7 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) if (!cur.selection()) { // Determine basis font LyXFont layoutfont; - par_type pit = cur.par(); + pit_type pit = cur.pit(); if (cur.pos() < pars_[pit].beginOfBody()) layoutfont = getLabelFont(pars_[pit]); else @@ -454,9 +425,6 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) // Ok, we have a selection. recordUndoSelection(cur); - par_type const beg = cur.selBegin().par(); - par_type const end = cur.selEnd().par(); - DocIterator dit = cur.selectionBegin(); DocIterator ditend = cur.selectionEnd(); @@ -464,15 +432,15 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) // Don't use forwardChar here as ditend might have // pos() == lastpos() and forwardChar would miss it. - for (; dit != ditend; dit.forwardPos()) { + // 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.par(), dit.pos(), f); + setCharFont(dit.pit(), dit.pos(), f); } } - - redoParagraphs(beg, end + 1); } @@ -482,7 +450,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()); } @@ -491,8 +459,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); } @@ -506,7 +475,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()); } @@ -556,7 +525,7 @@ string LyXText::getStringToIndex(LCursor & cur) 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); @@ -579,10 +548,10 @@ void LyXText::setParagraph(LCursor & cur, { BOOST_ASSERT(cur.text()); // make sure that the depth behind the selection are restored, too - par_type undopit = undoSpan(cur.selEnd().par()); - recUndo(cur.selBegin().par(), undopit - 1); + pit_type undopit = undoSpan(cur.selEnd().pit()); + recUndo(cur.selBegin().pit(), undopit - 1); - for (par_type pit = cur.selBegin().par(), end = cur.selEnd().par(); + for (pit_type pit = cur.selBegin().pit(), end = cur.selEnd().pit(); pit <= end; ++pit) { Paragraph & par = pars_[pit]; ParagraphParameters & params = par.params(); @@ -602,305 +571,6 @@ void LyXText::setParagraph(LCursor & cur, par.setLabelWidthString(labelwidthstring); params.noindent(noindent); } - - redoParagraphs(cur.selBegin().par(), undopit); -} - - -string expandLabel(LyXTextClass const & textclass, - LyXLayout_ptr const & layout, bool appendix) -{ - string fmt = appendix ? - layout->labelstring_appendix() : layout->labelstring(); - - // handle 'inherited level parts' in 'fmt', - // i.e. the stuff between '@' in '@Section@.\arabic{subsection}' - size_t const i = fmt.find('@', 0); - if (i != string::npos) { - size_t const j = fmt.find('@', i + 1); - if (j != string::npos) { - string parent(fmt, i + 1, j - i - 1); - string label = expandLabel(textclass, textclass[parent], appendix); - fmt = string(fmt, 0, i) + label + string(fmt, j + 1, string::npos); - } - } - - return textclass.counters().counterLabel(fmt); -} - - -namespace { - -void incrementItemDepth(ParagraphList & pars, par_type pit, par_type first_pit) -{ - int const cur_labeltype = pars[pit].layout()->labeltype; - - if (cur_labeltype != LABEL_ENUMERATE && cur_labeltype != LABEL_ITEMIZE) - return; - - int const cur_depth = pars[pit].getDepth(); - - par_type prev_pit = pit - 1; - while (true) { - 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) { - pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; - } - break; - } else if (prev_depth < cur_depth) { - if (prev_labeltype == cur_labeltype) { - pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; - break; - } - } else if (prev_depth == cur_depth) { - if (prev_labeltype == cur_labeltype) { - pars[pit].itemdepth = pars[prev_pit].itemdepth; - break; - } - } - if (prev_pit == first_pit) - break; - - --prev_pit; - } -} - - -void resetEnumCounterIfNeeded(ParagraphList & pars, par_type pit, - par_type firstpit, Counters & counters) -{ - if (pit == firstpit) - return; - - int const cur_depth = pars[pit].getDepth(); - par_type prev_pit = pit - 1; - while (true) { - 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 (pars[pit].itemdepth) { - case 0: - counters.reset("enumi"); - case 1: - counters.reset("enumii"); - case 2: - counters.reset("enumiii"); - case 3: - counters.reset("enumiv"); - } - } - break; - } - - if (prev_pit == firstpit) - break; - - --prev_pit; - } -} - -} // anon namespace - - -// set the counter of a paragraph. This includes the labels -void LyXText::setCounter(Buffer const & buf, par_type pit) -{ - Paragraph & par = pars_[pit]; - BufferParams const & bufparams = buf.params(); - LyXTextClass const & textclass = bufparams.getLyXTextClass(); - LyXLayout_ptr const & layout = par.layout(); - Counters & counters = textclass.counters(); - - // Always reset - par.itemdepth = 0; - - if (pit == 0) { - par.params().appendix(par.params().startOfAppendix()); - } else { - 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(pars_, pit, 0); - } - - // erase what was there before - par.params().labelString(string()); - - if (layout->margintype == MARGIN_MANUAL) { - if (par.params().labelWidthString().empty()) - par.setLabelWidthString(layout->labelstring()); - } else { - par.setLabelWidthString(string()); - } - - // is it a layout that has an automatic label? - if (layout->labeltype == LABEL_COUNTER) { - BufferParams const & bufparams = buf.params(); - LyXTextClass const & textclass = bufparams.getLyXTextClass(); - counters.step(layout->counter); - 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: - // par.params().labelString( - // bufparams.user_defined_bullet(par.itemdepth).getText()); - // for now, use a simple hardcoded label - string itemlabel; - switch (par.itemdepth) { - case 0: - itemlabel = "*"; - break; - case 1: - itemlabel = "-"; - break; - case 2: - itemlabel = "@"; - break; - case 3: - itemlabel = "ยท"; - break; - } - - par.params().labelString(itemlabel); - } else if (layout->labeltype == LABEL_ENUMERATE) { - // Maybe we have to reset the enumeration counter. - resetEnumCounterIfNeeded(pars_, pit, 0, counters); - - // FIXME - // Yes I know this is a really, really! bad solution - // (Lgb) - string enumcounter = "enum"; - - switch (par.itemdepth) { - case 2: - enumcounter += 'i'; - case 1: - enumcounter += 'i'; - case 0: - enumcounter += 'i'; - break; - case 3: - enumcounter += "iv"; - break; - default: - // not a valid enumdepth... - break; - } - - counters.step(enumcounter); - - par.params().labelString(counters.enumLabel(enumcounter)); - } else if (layout->labeltype == LABEL_BIBLIO) {// ale970302 - counters.step("bibitem"); - int number = counters.value("bibitem"); - if (par.bibitem()) { - par.bibitem()->setCounter(number); - par.params().labelString(layout->labelstring()); - } - // In biblio should't be following counters but... - } else { - string s = buf.B_(layout->labelstring()); - - // the caption hack: - if (layout->labeltype == LABEL_SENSITIVE) { - par_type end = paragraphs().size(); - par_type tmppit = pit; - InsetBase * in = 0; - bool isOK = false; - while (tmppit != end) { - in = pars_[tmppit].inInset(); - if (in->lyxCode() == InsetBase::FLOAT_CODE || - in->lyxCode() == InsetBase::WRAP_CODE) { - isOK = true; - break; - } -#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 sould use "Figure" as label - */ - else { - Paragraph const * owner = &ownerPar(buf, in); - tmppit = 0; - for ( ; tmppit != end; ++tmppit) - if (&pars_[tmppit] == owner) - break; - } -#endif - } - - if (isOK) { - string type; - - if (in->lyxCode() == InsetBase::FLOAT_CODE) - type = static_cast(in)->params().type; - else if (in->lyxCode() == InsetBase::WRAP_CODE) - type = static_cast(in)->params().type; - else - BOOST_ASSERT(false); - - Floating const & fl = textclass.floats().getType(type); - - counters.step(fl.type()); - - // Doesn't work... yet. - s = bformat(_("%1$s #:"), buf.B_(fl.name())); - } else { - // par->SetLayout(0); - // s = layout->labelstring; - s = _("Senseless: "); - } - } - par.params().labelString(s); - - } -} - - -// Updates all counters. -void LyXText::updateCounters() -{ - // start over - bv()->buffer()->params().getLyXTextClass().counters().reset(); - - bool update_pos = false; - - par_type end = paragraphs().size(); - for (par_type pit = 0; pit != end; ++pit) { - string const oldLabel = pars_[pit].params().labelString(); - size_t maxdepth = 0; - if (pit != 0) - maxdepth = pars_[pit - 1].getMaxDepthAfter(); - - if (pars_[pit].params().depth() > maxdepth) - pars_[pit].params().depth(maxdepth); - - // setCounter can potentially change the labelString. - setCounter(*bv()->buffer(), pit); - string const & newLabel = pars_[pit].params().labelString(); - if (oldLabel != newLabel) { - //lyxerr[Debug::DEBUG] << "changing labels: old: " << oldLabel << " new: " - // << newLabel << endl; - redoParagraphInternal(pit); - update_pos = true; - } - } - if (update_pos) - updateParPositions(); } @@ -910,25 +580,23 @@ void LyXText::insertInset(LCursor & cur, InsetBase * inset) BOOST_ASSERT(this == cur.text()); BOOST_ASSERT(inset); cur.paragraph().insertInset(cur.pos(), inset); - redoParagraph(cur); } // needed to insert the selection void LyXText::insertStringAsLines(LCursor & cur, string const & str) { - par_type pit = cur.par(); - par_type endpit = cur.par() + 1; + pit_type pit = cur.pit(); pos_type pos = cur.pos(); recordUndo(cur); // only to be sure, should not be neccessary cur.clearSelection(); - cur.buffer().insertStringAsLines(pars_, pit, pos, current_font, str); + cur.buffer().insertStringAsLines(pars_, pit, pos, current_font, str, + autoBreakRows_); - redoParagraphs(cur.par(), endpit); cur.resetAnchor(); - setCursor(cur, cur.par(), pos); + setCursor(cur, cur.pit(), pos); cur.setSelection(); } @@ -960,7 +628,7 @@ 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) { LCursor old = cur; @@ -969,23 +637,16 @@ bool LyXText::setCursor(LCursor & cur, par_type par, pos_type pos, } -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.pit() = par; cur.pos() = pos; cur.boundary() = boundary; - // no rows, no fun... - if (paragraphs().begin()->rows.empty()) - return; - // now some strict checking Paragraph & para = getPar(par); - Row const & row = *para.getRow(pos); - pos_type const end = row.endpos(); // None of these should happen, but we're scaredy-cats if (pos < 0) { @@ -996,24 +657,6 @@ void LyXText::setCursor(CursorSlice & cur, par_type par, if (pos > para.size()) { lyxerr << "dont like 1, pos: " << pos << " size: " << para.size() - << " row.pos():" << row.pos() - << " par: " << par << endl; - BOOST_ASSERT(false); - } - - if (pos > end) { - lyxerr << "dont like 2, pos: " << pos - << " size: " << para.size() - << " row.pos():" << row.pos() - << " par: " << par << endl; - // This shouldn't happen. - BOOST_ASSERT(false); - } - - if (pos < row.pos()) { - lyxerr << "dont like 3 please report pos:" << pos - << " size: " << para.size() - << " row.pos():" << row.pos() << " par: " << par << endl; BOOST_ASSERT(false); } @@ -1021,10 +664,10 @@ void LyXText::setCursor(CursorSlice & cur, par_type par, 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.top(), par, pos, boundary); - cur.x_target() = cursorX(cur.top()); + cur.setTargetX(); if (setfont) setCurrentFont(cur); } @@ -1072,10 +715,11 @@ 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(par_type const pit, +pos_type LyXText::getColumnNearX(pit_type const pit, Row const & row, int & x, bool & boundary) const { - x -= xo_; + int const xo = theCoords.get(this, pit).x_; + x -= xo; RowMetrics const r = computeRowMetrics(pit, row); Paragraph const & par = pars_[pit]; @@ -1097,7 +741,7 @@ pos_type LyXText::getColumnNearX(par_type const pit, // check for empty row if (vc == end) { - x = int(tmpx) + xo_; + x = int(tmpx) + xo; return 0; } @@ -1167,46 +811,55 @@ pos_type LyXText::getColumnNearX(par_type const pit, c = end - 1; } - x = int(tmpx) + xo_; + if (row.pos() < end && c >= end + && par.isInset(end) && par.getInset(end)->display()) { + c = end - 1; + } + + x = int(tmpx) + xo; return c - row.pos(); } -// y is relative to this LyXText's top -// this is only used in the two functions below -Row const & LyXText::getRowNearY(int y, par_type & pit) const +// y is screen coordinate +pit_type LyXText::getPitNearY(int y) const { BOOST_ASSERT(!paragraphs().empty()); - BOOST_ASSERT(!paragraphs().begin()->rows.empty()); - par_type const pend = paragraphs().size() - 1; - pit = 0; - while (int(pars_[pit].y + pars_[pit].height) < y && pit != pend) - ++pit; - - RowList::iterator rit = pars_[pit].rows.end(); - RowList::iterator const rbegin = pars_[pit].rows.begin(); - do { - --rit; - } while (rit != rbegin && int(pars_[pit].y + rit->y_offset()) > y); + 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_; + } + } - return *rit; + lyxerr << " found best y: " << yy << " for pit: " << pit << endl; + return pit; } -// x,y are absolute coordinates -// sets cursor only within this LyXText -void LyXText::setCursorFromCoordinates(LCursor & cur, int x, int y) +Row const & LyXText::getRowNearY(int y, pit_type pit) const { - x -= xo_; - y -= yo_; - par_type pit; - Row const & row = getRowNearY(y, pit); - lyxerr[Debug::DEBUG] << "setCursorFromCoordinates:: 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); - setCursor(cur, pit, pos, true, bound); + 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; } @@ -1214,21 +867,27 @@ void LyXText::setCursorFromCoordinates(LCursor & cur, int x, int y) // sets cursor recursively descending into nested editable insets InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const { - par_type 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() = 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); lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl; - if (!inset) + 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. @@ -1238,7 +897,10 @@ InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const // this inset. 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; } @@ -1256,93 +918,155 @@ bool LyXText::checkAndActivateInset(LCursor & cur, bool front) } -void LyXText::cursorLeft(LCursor & cur) +bool LyXText::cursorLeft(LCursor & cur) { if (cur.pos() != 0) { bool boundary = cur.boundary(); - setCursor(cur, cur.par(), cur.pos() - 1, true, false); + 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)) - setCursor(cur, cur.par(), cur.pos() + 1, true, true); + updateNeeded |= + setCursor(cur, cur.pit(), cur.pos() + 1, true, true); } - return; + return updateNeeded; } - if (cur.par() != 0) { - // steps into the paragraph above - setCursor(cur, cur.par() - 1, getPar(cur.par() - 1).size()); + if (cur.pit() != 0) { + // Steps into the paragraph above + return setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size()); } + return false; } -void LyXText::cursorRight(LCursor & cur) +bool LyXText::cursorRight(LCursor & cur) { if (false && cur.boundary()) { - setCursor(cur, cur.par(), cur.pos(), true, false); - return; + return setCursor(cur, cur.pit(), cur.pos(), true, false); } if (cur.pos() != cur.lastpos()) { + bool updateNeeded = false; if (!checkAndActivateInset(cur, true)) { - setCursor(cur, cur.par(), cur.pos() + 1, true, false); + updateNeeded |= setCursor(cur, cur.pit(), cur.pos() + 1, true, false); if (false && bidi.isBoundary(cur.buffer(), cur.paragraph(), cur.pos())) - setCursor(cur, cur.par(), cur.pos(), true, true); + updateNeeded |= setCursor(cur, cur.pit(), cur.pos(), true, true); } - return; + return updateNeeded; } - if (cur.par() != cur.lastpar()) - setCursor(cur, cur.par() + 1, 0); + if (cur.pit() != cur.lastpit()) + return setCursor(cur, cur.pit() + 1, 0); + return false; } -void LyXText::cursorUp(LCursor & cur) +bool LyXText::cursorUp(LCursor & cur) { - Row const & row = cur.textRow(); - int x = cur.x_target(); - int y = cursorY(cur.top()) - row.baseline() - 1; - setCursorFromCoordinates(cur, x, y); + Paragraph const & par = cur.paragraph(); + int const row = par.pos2row(cur.pos()); + int const x = cur.targetX(); if (!cur.selection()) { - InsetBase * inset_hit = checkInsetHit(cur.x_target(), y); - if (inset_hit && isHighlyEditableInset(inset_hit)) - inset_hit->editXY(cur, cur.x_target(), y); + 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); + } + + bool updateNeeded = false; + + if (row > 0) { + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), row - 1, x)); + } else if (cur.pit() > 0) { + --cur.pit(); + //cannot use 'par' now + updateNeeded |= setCursor(cur, cur.pit(), x2pos(cur.pit(), cur.paragraph().rows().size() - 1, x)); } + + cur.x_target() = x; + + return updateNeeded; } -void LyXText::cursorDown(LCursor & cur) +bool LyXText::cursorDown(LCursor & cur) { - Row const & row = cur.textRow(); - int x = cur.x_target(); - int y = cursorY(cur.top()) - row.baseline() + row.height() + 1; - setCursorFromCoordinates(cur, x, y); + Paragraph const & par = cur.paragraph(); + int const row = par.pos2row(cur.pos()); + int const x = cur.targetX(); if (!cur.selection()) { - InsetBase * inset_hit = checkInsetHit(cur.x_target(), y); - if (inset_hit && isHighlyEditableInset(inset_hit)) - inset_hit->editXY(cur, cur.x_target(), y); + int const y = bv_funcs::getPos(cur).y_; + LCursor old = cur; + editXY(cur, x, y + par.rows()[row].descent() + 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(); + + bool const changed = deleteEmptyParagraphMechanism(dummy, old); + + // Make sure that cur gets back whatever happened to dummy(Lgb) + if (changed) + cur = dummy; + + return changed; + + } + + bool updateNeeded = false; + + 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; } @@ -1350,16 +1074,16 @@ 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(); @@ -1368,13 +1092,12 @@ void LyXText::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where) bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) { - BOOST_ASSERT(cur.size() == old.size()); // Would be wrong to delete anything if we have a selection. if (cur.selection()) return false; //lyxerr[Debug::DEBUG] << "DEPM: cur:\n" << cur << "old:\n" << old << endl; - Paragraph const & oldpar = pars_[old.par()]; + Paragraph const & oldpar = pars_[old.pit()]; // We allow all kinds of "mumbo-jumbo" when freespacing. if (oldpar.isFreeSpacing()) @@ -1404,14 +1127,18 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) // MISSING // If the chars around the old cursor were spaces, delete one of them. - if (old.par() != cur.par() || old.pos() != cur.pos()) { + if (old.pit() != cur.pit() || old.pos() != cur.pos()) { // 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.par()].erase(old.pos() - 1); + // We need to set the text to Change::INSERTED to + // get it erased properly + pars_[old.pit()].setChange(old.pos() -1, + Change::INSERTED); + 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 @@ -1424,12 +1151,12 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) #warning DEPM, look here #endif //fixCursorAfterDelete(cur.anchor(), old.top()); - return false; + return true; } } // only do our magic if we changed paragraph - if (old.par() == cur.par()) + if (old.pit() == cur.pit()) return false; // don't delete anything if this is the ONLY paragraph! @@ -1446,30 +1173,28 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) { // ok, we will delete something - CursorSlice tmpcursor; - deleted = true; bool selection_position_was_oldcursor_position = - cur.anchor().par() == old.par() && cur.anchor().pos() == old.pos(); + cur.anchor().pit() == old.pit() && cur.anchor().pos() == old.pos(); // This is a bit of a overkill. We change the old and the cur par // at max, certainly not everything in between... - recUndo(old.par(), cur.par()); + recUndo(old.pit(), cur.pit()); // Delete old par. - pars_.erase(pars_.begin() + old.par()); + pars_.erase(pars_.begin() + old.pit()); // Update cursor par offset if necessary. // Some 'iterator registration' would be nice that takes care of // such events. Maybe even signal/slot? - if (cur.par() > old.par()) - --cur.par(); + if (cur.pit() > old.pit()) + --cur.pit(); #ifdef WITH_WARNINGS #warning DEPM, look here #endif -// if (cur.anchor().par() > old.par()) -// --cur.anchor().par(); +// if (cur.anchor().pit() > old.pit()) +// --cur.anchor().pit(); if (selection_position_was_oldcursor_position) { // correct selection @@ -1480,7 +1205,7 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) if (deleted) return true; - if (pars_[old.par()].stripLeadingSpaces()) + if (pars_[old.pit()].stripLeadingSpaces()) cur.resetAnchor(); return false; @@ -1493,13 +1218,13 @@ ParagraphList & LyXText::paragraphs() const } -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); }