#include <config.h>
#include "Buffer.h"
+#include "BufferParams.h"
#include "BufferView.h"
#include "CoordCache.h"
#include "Cursor.h"
}
-// this (intentionally) does neither touch anchor nor selection status
void Cursor::setCursor(DocIterator const & cur)
{
DocIterator::operator=(cur);
}
+void Cursor::setCursorSelectionTo(DocIterator dit)
+{
+ size_t i = 0;
+ // normalise dit
+ while (i < dit.depth() && i < anchor_.depth() && dit[i] == anchor_[i])
+ ++i;
+ if (i != dit.depth()) {
+ // otherwise the cursor is already normal
+ if (i == anchor_.depth())
+ // dit is a proper extension of the anchor_
+ dit.cutOff(i - 1);
+ else if (i + 1 < dit.depth()) {
+ // one has dit[i] != anchor_[i] but either dit[i-1] == anchor_[i-1]
+ // or i == 0. Remove excess.
+ dit.cutOff(i);
+ if (dit[i] > anchor_[i])
+ // place dit after the inset it was in
+ ++dit.pos();
+ }
+ }
+ setCursor(dit);
+ setSelection();
+}
+
+
void Cursor::setCursorToAnchor()
{
if (selection()) {
}
-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
right_pos = -1;
Row const & row = textRow();
- TextMetrics const & tm = bv_->textMetrics(text());
double dummy = 0;
- Row::const_iterator cit = tm.findRowElement(row, pos(), boundary(), dummy);
+ Row::const_iterator cit = row.findElement(pos(), boundary(), dummy);
// Handle the case of empty row
if (cit == row.end()) {
- if (paragraph().isRTL(buffer()->params()))
+ if (row.isRTL())
right_pos = row.pos();
else
left_pos = row.pos() - 1;
bool Cursor::posVisToNewRow(bool movingLeft)
{
- Paragraph const & par = paragraph();
- Buffer const & buf = *buffer();
Row const & row = textRow();
- bool par_is_LTR = !par.isRTL(buf.params());
+ bool par_is_LTR = !row.isRTL();
// Inside a table, determining whether to move to the next or
// previous row should be done based on the table's direction.
}
-bool Cursor::backspace()
+bool Cursor::backspace(bool const force)
{
if (selection()) {
cap::eraseSelection(*this);
}
}
- 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();
}
-bool Cursor::erase()
+bool Cursor::erase(bool const force)
{
if (inMacroMode())
return true;
}
// '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();
bool keep_mathmode = it != words.end() && (it->second.inset == "font"
|| it->second.inset == "oldfont"
|| it->second.inset == "mbox");
- bool ert_macro = !user_macro && it == words.end();
+ bool ert_macro = !user_macro && it == words.end() && atomAsMacro;
if (in && in->currentMode() == Inset::TEXT_MODE
&& atom.nucleus()->currentMode() == Inset::MATH_MODE
<< pos() << ' ' << lastpos() << " in idx: " << idx()
<< " in atom: '";
odocstringstream os;
- otexrowstream ots(os, false);
+ otexrowstream ots(os);
WriteStream wi(ots, false, true, WriteStream::wsDefault);
inset().asInsetMath()->write(wi);
lyxerr << to_utf8(os.str()) << endl;
}
+InsetMath & Cursor::nextMath()
+{
+ return *nextAtom().nucleus();
+}
+
+
+InsetMath & Cursor::prevMath()
+{
+ return *prevAtom().nucleus();
+}
+
+
+bool Cursor::mathForward(bool word)
+{
+ LASSERT(inMathed(), return false);
+ if (pos() < lastpos()) {
+ if (word) {
+ // word: skip a group of insets with same math class
+ MathClass mc = nextMath().mathClass();
+ do
+ posForward();
+ while (pos() < lastpos() && mc == nextMath().mathClass());
+ } else if (openable(nextAtom())) {
+ // single step: try to enter the next inset
+ pushBackward(nextMath());
+ inset().idxFirst(*this);
+ } else
+ posForward();
+ return true;
+ }
+ if (inset().idxForward(*this))
+ return true;
+ // try to pop forwards --- but don't pop out of math! leave that to
+ // the FINISH lfuns
+ int s = depth() - 2;
+ if (s >= 0 && operator[](s).inset().asInsetMath())
+ return popForward();
+ return false;
+}
+
+
+bool Cursor::mathBackward(bool word)
+{
+ LASSERT(inMathed(), return false);
+ if (pos() > 0) {
+ if (word) {
+ // word: skip a group of insets with same math class
+ MathClass mc = prevMath().mathClass();
+ do
+ posBackward();
+ while (pos() > 0 && mc == prevMath().mathClass());
+ } else if (openable(prevAtom())) {
+ // single step: try to enter the preceding inset
+ posBackward();
+ push(nextMath());
+ inset().idxLast(*this);
+ } else
+ posBackward();
+ return true;
+ }
+ if (inset().idxBackward(*this))
+ return true;
+ // try to pop backwards --- but don't pop out of math! leave that to
+ // the FINISH lfuns
+ int s = depth() - 2;
+ if (s >= 0 && operator[](s).inset().asInsetMath())
+ return popBackward();
+ return false;
+}
+
+
bool Cursor::atFirstOrLastRow(bool up)
{
TextMetrics const & tm = bv_->textMetrics(text());
{
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(
- bv().buffer().params(), sl.pos(), text.outerFont(sl.pit()));
+ Font font = text.getPar(sl.pit()).getFont(bp, sl.pos(),
+ text.outerFont(sl.pit()));
return font.language()->encoding();
}
// The logic here should more or less match to the
// Cursor::setCurrentFont logic, i.e. the cursor height should
// give a hint what will happen if a character is entered.
+ // FIXME: this is not the case, what about removing this method ? (see #10478).
// HACK. far from being perfect...
{
setBuffer(&bv_->buffer());
DocIterator::sanitize();
+ new_word_.sanitize();
if (selection())
anchor_.sanitize();
else
}
+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();
+ int const wid = insetCache.dim(inset).wid;
+ Point p = insetCache.xy(inset);
+ if (x > p.x_ + (wid + 1) / 2)
+ posForward();
+ }
+}
+
+
} // namespace lyx