X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCursor.cpp;h=92c9bdda2639161664d5b3d31efa6b85e851e1c1;hb=e694199837172dd4927eb64112e00f85a426eb8e;hp=378a138da6b20c0c3daa7e3883d1aaa7a7d35834;hpb=1fca708c7f33f089055d8ca258d8cd6a357cf2a6;p=lyx.git diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 378a138da6..92c9bdda26 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -21,7 +21,6 @@ #include "Cursor.h" #include "CutAndPaste.h" #include "DispatchResult.h" -#include "Encoding.h" #include "Font.h" #include "FuncCode.h" #include "FuncRequest.h" @@ -53,7 +52,7 @@ #include "mathed/MacroTable.h" #include "mathed/MathData.h" #include "mathed/MathFactory.h" -#include "mathed/MathMacro.h" +#include "mathed/InsetMathMacro.h" #include #include @@ -115,7 +114,7 @@ DocIterator bruteFind(Cursor const & c, int x, int y) } -} // namespace anon +} // namespace CursorData::CursorData() @@ -454,19 +453,6 @@ int Cursor::currentMode() } -bool Cursor::inCoordCache() const -{ - // the root inset is not in cache, but we do not need it. - if (depth() == 1) - return true; - CoordCache::Insets const & icache = bv_->coordCache().getInsets(); - for (size_t i = 1 ; i < depth() ; ++i) - if (!icache.has(&(*this)[i].inset())) - return false; - return true; -} - - void Cursor::getPos(int & x, int & y) const { Point p = bv().getPos(*this); @@ -551,24 +537,6 @@ void Cursor::checkNewWordPosition() } -bool Cursor::posBackward() -{ - if (pos() == 0) - return false; - --pos(); - return true; -} - - -bool Cursor::posForward() -{ - if (pos() == lastpos()) - return false; - ++pos(); - return true; -} - - bool Cursor::posVisRight(bool skip_inset) { Cursor new_cur = *this; // where we will move to @@ -776,7 +744,7 @@ bool findNonVirtual(Row const & row, Row::const_iterator & cit, bool onleft) return cit != row.end() && !cit->isVirtual(); } -} +} // namespace void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos) const { @@ -1075,7 +1043,7 @@ void Cursor::updateTextTargetOffset() } -void Cursor::info(odocstream & os) const +void Cursor::info(odocstream & os, bool devel_mode) const { for (int i = 1, n = depth(); i < n; ++i) { operator[](i).inset().infoize(os); @@ -1087,6 +1055,14 @@ void Cursor::info(odocstream & os) const if (inset) prevInset()->infoize2(os); } + if (devel_mode) { + InsetMath * math = inset().asInsetMath(); + if (math) + os << _(", Inset: ") << math->id(); + os << _(", Cell: ") << idx(); + os << _(", Position: ") << pos(); + } + } @@ -1301,7 +1277,7 @@ void Cursor::insert(MathData const & ar) } -bool Cursor::backspace() +bool Cursor::backspace(bool const force) { if (selection()) { cap::eraseSelection(*this); @@ -1337,7 +1313,7 @@ bool Cursor::backspace() } } - if (pos() != 0 && prevAtom()->nargs() > 0) { + if (pos() != 0 && !force && prevAtom()->confirmDeletion()) { // let's require two backspaces for 'big stuff' and // highlight on the first resetAnchor(); @@ -1351,7 +1327,7 @@ bool Cursor::backspace() } -bool Cursor::erase() +bool Cursor::erase(bool const force) { if (inMacroMode()) return true; @@ -1386,7 +1362,7 @@ bool Cursor::erase() } // 'clever' UI hack: only erase large items if previously slected - if (pos() != lastpos() && nextAtom()->nargs() > 0) { + if (pos() != lastpos() && !force && nextAtom()->confirmDeletion()) { resetAnchor(); selection(true); ++pos(); @@ -1424,7 +1400,7 @@ bool Cursor::down() } -bool Cursor::macroModeClose() +bool Cursor::macroModeClose(bool cancel) { if (!inMacroMode()) return false; @@ -1436,25 +1412,26 @@ bool Cursor::macroModeClose() --pos(); cell().erase(pos()); - // do nothing if the macro name is empty - if (s == "\\") - return false; - // trigger updates of macros, at least, if no full // updates take place anyway screenUpdateFlags(Update::Force); + // do nothing if the macro name is empty + if (s == "\\" || cancel) { + return false; + } + docstring const name = s.substr(1); InsetMathNest * const in = inset().asInsetMath()->asNestInset(); if (in && in->interpretString(*this, s)) return true; bool const user_macro = buffer()->getMacro(name, *this, false); - MathAtom atom = user_macro ? MathAtom(new MathMacro(buffer(), name)) + MathAtom atom = user_macro ? MathAtom(new InsetMathMacro(buffer(), name)) : createInsetMath(name, buffer()); // try to put argument into macro, if we just inserted a macro bool macroArg = false; - MathMacro * atomAsMacro = atom.nucleus()->asMacro(); + InsetMathMacro * atomAsMacro = atom.nucleus()->asMacro(); if (atomAsMacro) { // macros here are still unfolded (in init mode in fact). So // we have to resolve the macro here manually and check its arity @@ -1462,10 +1439,10 @@ bool Cursor::macroModeClose() MacroData const * data = buffer()->getMacro(atomAsMacro->name()); if (!selection.empty() && data && data->numargs() - data->optionals() > 0) { macroArg = true; - atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 1); + atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 1); } else // non-greedy case. Do not touch the arguments behind - atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT, 0); + atomAsMacro->setDisplayMode(InsetMathMacro::DISPLAY_INTERACTIVE_INIT, 0); } // insert remembered selection into first argument of a non-macro @@ -1474,9 +1451,10 @@ bool Cursor::macroModeClose() MathWordList const & words = mathedWordList(); MathWordList::const_iterator it = words.find(name); - bool keep_mathmode = it != words.end() && (it->second.inset == "font" - || it->second.inset == "oldfont" - || it->second.inset == "mbox"); + bool keep_mathmode = user_macro + || (it != words.end() && (it->second.inset == "font" + || it->second.inset == "oldfont" + || it->second.inset == "mbox")); bool ert_macro = !user_macro && it == words.end() && atomAsMacro; if (in && in->currentMode() == Inset::TEXT_MODE @@ -1756,11 +1734,23 @@ bool Cursor::mathForward(bool word) LASSERT(inMathed(), return false); if (pos() < lastpos()) { if (word) { - // word: skip a group of insets with same math class + // word: skip a group of insets of the form X*(B*|R*|P*) (greedy + // match) where X is any math class, B is mathbin, R is mathrel, and + // P is mathpunct. Make sure that the following remains true: + // mathForward(true); mathBackward(true); mathForward(true) + // is the same as mathForward(true) and + // mathBackward(true); mathForward(true); mathBackward(true) + // is the same as mathBackward(true). MathClass mc = nextMath().mathClass(); do posForward(); while (pos() < lastpos() && mc == nextMath().mathClass()); + if (pos() < lastpos() && + ((mc = nextMath().mathClass()) == MC_BIN || + mc == MC_REL || mc == MC_PUNCT)) + do + posForward(); + while (pos() < lastpos() && mc == nextMath().mathClass()); } else if (openable(nextAtom())) { // single step: try to enter the next inset pushBackward(nextMath()); @@ -1785,11 +1775,17 @@ bool Cursor::mathBackward(bool word) LASSERT(inMathed(), return false); if (pos() > 0) { if (word) { - // word: skip a group of insets with same math class + // word: skip a group of insets. See the comment in mathForward. MathClass mc = prevMath().mathClass(); do posBackward(); while (pos() > 0 && mc == prevMath().mathClass()); + if (pos() > 0 && (mc == MC_BIN || mc == MC_REL || mc == MC_PUNCT)) { + mc = prevMath().mathClass(); + do + posBackward(); + while (pos() > 0 && mc == prevMath().mathClass()); + } } else if (openable(prevAtom())) { // single step: try to enter the preceding inset posBackward(); @@ -1924,10 +1920,13 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) int yo = bv().getPos(*this).y_; Cursor old = *this; // To next/previous row + // FIXME: the y position is often guessed wrongly across styles and + // insets, which leads to weird behaviour. if (up) tm.editXY(*this, xo, yo - textRow().ascent() - 1); else tm.editXY(*this, xo, yo + textRow().descent() + 1); + x_target_ = old.x_target_; clearSelection(); // This happens when you move out of an inset. @@ -1976,6 +1975,8 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) bool bound = false; top().pos() = tm.getPosNearX(real_next_row, xo, bound); boundary(bound); + // When selection==false, this is done by TextMetrics::editXY + setCurrentFont(); updateNeeded |= bv().checkDepm(*this, old); } @@ -2051,7 +2052,7 @@ docstring parbreak(Cursor const * cur) return os.str(); } -} +} // namespace docstring Cursor::selectionAsString(bool with_label) const @@ -2103,23 +2104,16 @@ docstring Cursor::selectionAsString(bool with_label) const } -docstring Cursor::currentState() const +docstring Cursor::currentState(bool devel_mode) const { if (inMathed()) { odocstringstream os; - info(os); -#ifdef DEVEL_VERSION - InsetMath * math = inset().asInsetMath(); - if (math) - os << _(", Inset: ") << math->id(); - os << _(", Cell: ") << idx(); - os << _(", Position: ") << pos(); -#endif + info(os, devel_mode); return os.str(); } if (inTexted()) - return text()->currentState(*this); + return text()->currentState(*this, devel_mode); return docstring(); } @@ -2131,22 +2125,6 @@ docstring Cursor::getPossibleLabel() const } -Encoding const * Cursor::getEncoding() const -{ - if (empty()) - return 0; - BufferParams const & bp = bv().buffer().params(); - if (bp.useNonTeXFonts) - return encodings.fromLyXName("utf8-plain"); - - CursorSlice const & sl = innerTextSlice(); - Text const & text = *sl.text(); - Font font = text.getPar(sl.pit()).getFont(bp, sl.pos(), - text.outerFont(sl.pit())); - return font.language()->encoding(); -} - - void Cursor::undispatched() const { disp_.dispatched(false); @@ -2436,4 +2414,39 @@ void Cursor::checkBufferStructure() } +bool Cursor::confirmDeletion(bool const before) const +{ + if (!selection()) { + if (Inset const * inset = before ? prevInset() : nextInset()) + return inset->confirmDeletion(); + } else { + DocIterator dit = selectionBegin(); + CursorSlice const end = selectionEnd().top(); + for (; dit.top() < end; dit.top().forwardPos()) + if (Inset const * inset = dit.nextInset()) + if (inset->confirmDeletion()) + return true; + } + return false; +} + + +void Cursor::moveToClosestEdge(int const x, bool const edit) +{ + if (Inset const * inset = nextInset()) { + // stay in front of insets for which we want to open the dialog + // (e.g. InsetMathSpace). + if (edit && (inset->hasSettings() || !inset->contextMenuName().empty())) + return; + CoordCache::Insets const & insetCache = bv().coordCache().getInsets(); + if (!insetCache.has(inset)) + return; + int const wid = insetCache.dim(inset).wid; + Point p = insetCache.xy(inset); + if (x > p.x_ + (wid + 1) / 2) + posForward(); + } +} + + } // namespace lyx