#include "Cursor.h"
#include "CutAndPaste.h"
#include "DispatchResult.h"
-#include "Encoding.h"
#include "Font.h"
#include "FuncCode.h"
#include "FuncRequest.h"
#include "mathed/MacroTable.h"
#include "mathed/MathData.h"
#include "mathed/MathFactory.h"
-#include "mathed/MathMacro.h"
+#include "mathed/InsetMathMacro.h"
#include <sstream>
#include <limits>
}
-} // namespace anon
+} // namespace
CursorData::CursorData()
}
-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);
return cit != row.end() && !cit->isVirtual();
}
-}
+} // namespace
void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos) const
{
}
+int Cursor::countInsetsInSelection(InsetCode const & inset_code)
+{
+ if (!selection_)
+ return 0;
+
+ DocIterator from, to;
+ from = selectionBegin();
+ to = selectionEnd();
+
+ int count = 0;
+
+ if (!from.nextInset()) //move to closest inset
+ from.forwardInset();
+
+ while (!from.empty() && from < to) {
+ Inset * inset = from.nextInset();
+ if (!inset)
+ break;
+ if (inset->lyxCode() == inset_code)
+ count ++;
+ from.forwardInset();
+ }
+ return count;
+}
+
+
+bool Cursor::insetInSelection(InsetCode const & inset_code)
+{
+ if (!selection_)
+ return false;
+
+ DocIterator from, to;
+ from = selectionBegin();
+ to = selectionEnd();
+
+ if (!from.nextInset()) //move to closest inset
+ from.forwardInset();
+
+ while (!from.empty() && from < to) {
+ Inset * inset = from.nextInset();
+ if (!inset)
+ break;
+ if (inset->lyxCode() == inset_code)
+ return true;
+ from.forwardInset();
+ }
+ return false;
+}
+
+
void Cursor::setTargetX(int x)
{
x_target_ = x;
}
-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);
if (inset)
prevInset()->infoize2(os);
}
+ if (devel_mode) {
+ InsetMath * math = inset().asInsetMath();
+ if (math)
+ os << _(", Inset: ") << math->id();
+ os << _(", Cell: ") << idx();
+ os << _(", Position: ") << pos();
+ }
+
}
// [|], can not delete from inside
return false;
} else {
- if (inMathed())
- pullArg();
- else
+ if (inMathed()) {
+ switch (inset().asInsetMath()->getType()) {
+ case hullEqnArray:
+ case hullAlign:
+ case hullFlAlign: {
+ FuncRequest cmd(LFUN_CHAR_BACKWARD);
+ this->dispatch(cmd);
+ break;
+ }
+ default:
+ pullArg();
+ break;
+ }
+ } else
popBackward();
return true;
}
}
-bool Cursor::macroModeClose()
+bool Cursor::macroModeClose(bool cancel)
{
if (!inMacroMode())
return false;
--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
// to put the selection behind it if arity > 0.
MacroData const * data = buffer()->getMacro(atomAsMacro->name());
- if (!selection.empty() && data && data->numargs() - data->optionals() > 0) {
+ if (!selection.empty() && data && data->numargs()) {
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
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
void Cursor::handleNest(MathAtom const & a, int c)
{
//lyxerr << "Cursor::handleNest: " << c << endl;
+ InsetMath const * im = selectionBegin().inset().asInsetMath();
+ Parse::flags const f = im && im->currentMode() != InsetMath::MATH_MODE
+ ? Parse::TEXTMODE : Parse::NORMAL;
MathAtom t = a;
- asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
+ asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c), f);
insert(t);
posBackward();
pushBackward(*nextInset());
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());
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();
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.
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);
}
return os.str();
}
-}
+} // namespace
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();
}
}
-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);
return inset->confirmDeletion();
} else {
DocIterator dit = selectionBegin();
- DocIterator const sel_end = selectionEnd();
- for (; dit < sel_end; dit.posForward())
+ CursorSlice const end = selectionEnd().top();
+ for (; dit.top() < end; dit.top().forwardPos())
if (Inset const * inset = dit.nextInset())
if (inset->confirmDeletion())
return true;
}
+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