X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext2.C;h=673287fbbb595796f0fedb4242fbf7cb15b9ebde;hb=3c851f1f7951f3a24b57826f3e580e4318b5e6c4;hp=8dad53a82a89c9f0c5312ea89a15b60796beccbf;hpb=ed064bdee611821c1ebdac78b7a085dfde9f0b5a;p=lyx.git diff --git a/src/text2.C b/src/text2.C index 8dad53a82a..673287fbbb 100644 --- a/src/text2.C +++ b/src/text2.C @@ -58,7 +58,7 @@ #include "support/lstrings.h" #include "support/textutils.h" -#include "support/tostr.h" +#include "support/convert.h" #include @@ -72,9 +72,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,15 +84,15 @@ 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; pit_type const end = paragraphs().size(); for (pit_type pit = 0; pit != end; ++pit) - pars_[pit].rows.clear(); + pars_[pit].rows().clear(); current_font = getFont(pars_[0], 0); - redoParagraphs(0, end); updateCounters(); } @@ -102,40 +103,35 @@ bool LyXText::isMainText() const } -// takes absolute x,y coordinates +//takes screen x,y coordinates InsetBase * LyXText::checkInsetHit(int x, int y) const { - pit_type pit; - pit_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; @@ -340,8 +336,7 @@ void LyXText::setLayout(LCursor & cur, string const & layout) pit_type start = cur.selBegin().pit(); pit_type end = cur.selEnd().pit() + 1; - pit_type endpit = setLayout(start, end, layout); - redoParagraphs(start, endpit); + setLayout(start, end, layout); updateCounters(); } @@ -349,18 +344,6 @@ void LyXText::setLayout(LCursor & cur, string const & layout) namespace { -void getSelectionSpan(LCursor & cur, pit_type & beg, pit_type & end) -{ - if (!cur.selection()) { - beg = cur.pit(); - end = cur.pit() + 1; - } else { - beg = cur.selBegin().pit(); - end = cur.selEnd().pit() + 1; - } -} - - bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, Paragraph const & par, int max_depth) { @@ -381,11 +364,9 @@ bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const { BOOST_ASSERT(this == cur.text()); - pit_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 (pit_type pit = beg; pit != end; ++pit) { if (::changeDepthAllowed(type, pars_[pit], max_depth)) @@ -399,23 +380,21 @@ bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const void LyXText::changeDepth(LCursor & cur, DEPTH_CHANGE type) { BOOST_ASSERT(this == cur.text()); - pit_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 = 0; - if (beg != 0) - max_depth = pars_[beg - 1].getMaxDepthAfter(); + 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)) { - int const depth = pars_[pit].params().depth(); + 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 @@ -454,9 +433,6 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) // Ok, we have a selection. recordUndoSelection(cur); - pit_type const beg = cur.selBegin().pit(); - pit_type const end = cur.selEnd().pit(); - DocIterator dit = cur.selectionBegin(); DocIterator ditend = cur.selectionEnd(); @@ -464,15 +440,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.pit(), dit.pos(), f); } } - - redoParagraphs(beg, end + 1); } @@ -491,6 +467,7 @@ 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.pit(), end == cur.lastpos() ? end : end - 1); } @@ -602,8 +579,6 @@ void LyXText::setParagraph(LCursor & cur, par.setLabelWidthString(labelwidthstring); params.noindent(noindent); } - - redoParagraphs(cur.selBegin().pit(), undopit); } @@ -818,8 +793,10 @@ void LyXText::setCounter(Buffer const & buf, pit_type pit) bool isOK = false; while (tmppit != end) { in = pars_[tmppit].inInset(); - if (in->lyxCode() == InsetBase::FLOAT_CODE || - in->lyxCode() == InsetBase::WRAP_CODE) { + // FIXME: in should be always valid. + if (in && + (in->lyxCode() == InsetBase::FLOAT_CODE || + in->lyxCode() == InsetBase::WRAP_CODE)) { isOK = true; break; } @@ -897,12 +874,9 @@ void LyXText::updateCounters() if (oldLabel != newLabel) { //lyxerr[Debug::DEBUG] << "changing labels: old: " << oldLabel << " new: " // << newLabel << endl; - redoParagraphInternal(pit); update_pos = true; } } - if (update_pos) - updateParPositions(); } @@ -912,7 +886,6 @@ void LyXText::insertInset(LCursor & cur, InsetBase * inset) BOOST_ASSERT(this == cur.text()); BOOST_ASSERT(inset); cur.paragraph().insertInset(cur.pos(), inset); - redoParagraph(cur); } @@ -920,15 +893,14 @@ void LyXText::insertInset(LCursor & cur, InsetBase * inset) void LyXText::insertStringAsLines(LCursor & cur, string const & str) { pit_type pit = cur.pit(); - pit_type endpit = cur.pit() + 1; 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.pit(), endpit); cur.resetAnchor(); setCursor(cur, cur.pit(), pos); cur.setSelection(); @@ -975,19 +947,12 @@ void LyXText::setCursor(CursorSlice & cur, pit_type par, pos_type pos, bool boundary) { BOOST_ASSERT(par != int(paragraphs().size())); - 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) { @@ -998,24 +963,6 @@ void LyXText::setCursor(CursorSlice & cur, pit_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); } @@ -1026,7 +973,7 @@ void LyXText::setCursorIntern(LCursor & cur, 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); } @@ -1077,7 +1024,8 @@ void LyXText::setCurrentFont(LCursor & cur) 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]; @@ -1099,7 +1047,7 @@ pos_type LyXText::getColumnNearX(pit_type const pit, // check for empty row if (vc == end) { - x = int(tmpx) + xo_; + x = int(tmpx) + xo; return 0; } @@ -1169,46 +1117,50 @@ pos_type LyXText::getColumnNearX(pit_type const pit, c = end - 1; } - x = int(tmpx) + xo_; + 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, pit_type & pit) const +// y is screen coordinate +pit_type LyXText::getPitNearY(int y) const { BOOST_ASSERT(!paragraphs().empty()); - BOOST_ASSERT(!paragraphs().begin()->rows.empty()); - pit_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_; - pit_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; } @@ -1216,8 +1168,9 @@ 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 { - pit_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 @@ -1225,12 +1178,17 @@ InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const 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. @@ -1240,7 +1198,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; } @@ -1258,93 +1219,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.pit(), 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.pit(), cur.pos() + 1, true, true); + updateNeeded |= + setCursor(cur, cur.pit(), cur.pos() + 1, true, true); } - return; + return updateNeeded; } if (cur.pit() != 0) { - // steps into the paragraph above - setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size()); + // 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.pit(), 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.pit(), 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.pit(), cur.pos(), true, true); + updateNeeded |= setCursor(cur, cur.pit(), cur.pos(), true, true); } - return; + return updateNeeded; } if (cur.pit() != cur.lastpit()) - setCursor(cur, cur.pit() + 1, 0); + 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(); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), par.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.pit(), 0); + updated = setCursor(cur, cur.pit(), 0); else if (cur.pit() != 0) - setCursor(cur, cur.pit() - 1, 0); + updated = setCursor(cur, cur.pit() - 1, 0); + return updated; } -void LyXText::cursorDownParagraph(LCursor & cur) +bool LyXText::cursorDownParagraph(LCursor & cur) { + bool updated = false; if (cur.pit() != cur.lastpit()) - setCursor(cur, cur.pit() + 1, 0); + updated = setCursor(cur, cur.pit() + 1, 0); else - setCursor(cur, cur.pit(), cur.lastpos()); + updated = setCursor(cur, cur.pit(), cur.lastpos()); + return updated; } @@ -1352,16 +1375,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.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(); @@ -1370,7 +1393,6 @@ 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; @@ -1426,7 +1448,7 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) #warning DEPM, look here #endif //fixCursorAfterDelete(cur.anchor(), old.top()); - return false; + return true; } } @@ -1448,8 +1470,6 @@ 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 =