]> git.lyx.org Git - lyx.git/blobdiff - src/Cursor.cpp
make frontend::Application a bit slimmer
[lyx.git] / src / Cursor.cpp
index e6cea1ff9507b91b45bb9692e766cd3b8f024712..ba348aa3576366f71d8bb9f2e77db52ca91f8cd1 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "Bidi.h"
 #include "BufferView.h"
-#include "bufferview_funcs.h"
 #include "Buffer.h"
 #include "Cursor.h"
 #include "CoordCache.h"
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParIterator.h"
+#include "TextMetrics.h"
+
+#include "support/docstream.h"
 
 #include "insets/InsetTabular.h"
 #include "insets/InsetText.h"
 
-#include "mathed/MathData.h"
 #include "mathed/InsetMath.h"
 #include "mathed/InsetMathScript.h"
 #include "mathed/MacroTable.h"
-
-#include "support/limited_stack.h"
+#include "mathed/MathData.h"
+#include "mathed/MathMacro.h"
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
@@ -97,9 +98,9 @@ namespace {
                        int xo;
                        int yo;
                        Inset const * inset = &it.inset();
-                       std::map<Inset const *, Point> const & data =
+                       std::map<Inset const *, Geometry> const & data =
                                c.bv().coordCache().getInsets().getData();
-                       std::map<Inset const *, Point>::const_iterator I = data.find(inset);
+                       std::map<Inset const *, Geometry>::const_iterator I = data.find(inset);
 
                        // FIXME: in the case where the inset is not in the cache, this
                        // means that no part of it is visible on screen. In this case
@@ -110,7 +111,7 @@ namespace {
                                return it;
                        }
 
-                       Point o = I->second;
+                       Point o = I->second.pos;
                        inset->cursorPos(c.bv(), it.top(), c.boundary(), xo, yo);
                        // Convert to absolute
                        xo += o.x_;
@@ -118,8 +119,8 @@ namespace {
                        double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
                        // '<=' in order to take the last possible position
                        // this is important for clicking behind \sum in e.g. '\sum_i a'
-                       LYXERR(Debug::DEBUG) << "i: " << i << " d: " << d
-                               << " best: " << best_dist << endl;
+                       LYXERR(Debug::DEBUG, "i: " << i << " d: " << d
+                               << " best: " << best_dist);
                        if (d <= best_dist) {
                                best_dist = d;
                                result = it;
@@ -132,6 +133,7 @@ namespace {
        }
 
 
+       /*
        /// moves position closest to (x, y) in given box
        bool bruteFind(Cursor & cursor,
                int x, int y, int xlow, int xhigh, int ylow, int yhigh)
@@ -161,7 +163,7 @@ namespace {
                for ( ; it != et; it.forwardPos(true)) {
                        // avoid invalid nesting when selecting
                        if (!cursor.selection() || positionable(it, cursor.anchor_)) {
-                               Point p = bv_funcs::getPos(bv, it, false);
+                               Point p = bv.getPos(it, false);
                                int xo = p.x_;
                                int yo = p.y_;
                                if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
@@ -186,6 +188,7 @@ namespace {
 
                return false;
        }
+       */
 
 
        /// moves position closest to (x, y) in given box
@@ -206,7 +209,7 @@ namespace {
                //      << " xlow: " << xlow << " xhigh: " << xhigh
                //      << " ylow: " << ylow << " yhigh: " << yhigh
                //      << endl;
-               Inset & inset = bv.buffer()->inset();
+               Inset & inset = bv.buffer().inset();
                DocIterator it = doc_iterator_begin(inset);
                it.pit() = from;
                DocIterator et = doc_iterator_end(inset);
@@ -216,9 +219,9 @@ namespace {
 
                for ( ; it != et; it.forwardPos()) {
                        // avoid invalid nesting when selecting
-                       if (bv_funcs::status(&bv, it) == bv_funcs::CUR_INSIDE
+                       if (bv.cursorStatus(it) == CUR_INSIDE
                            && (!cur.selection() || positionable(it, cur.anchor_))) {
-                               Point p = bv_funcs::getPos(bv, it, false);
+                               Point p = bv.getPos(it, false);
                                int xo = p.x_;
                                int yo = p.y_;
                                if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
@@ -253,8 +256,8 @@ namespace {
                odocstringstream ods;
                ods << '\n';
                // only add blank line if we're not in an ERT or Listings inset
-               if (par.ownerCode() != Inset::ERT_CODE
-                   && par.ownerCode() != Inset::LISTINGS_CODE)
+               if (par.ownerCode() != ERT_CODE
+                   && par.ownerCode() != LISTINGS_CODE)
                        ods << '\n';
                return ods.str();
        }
@@ -266,7 +269,8 @@ namespace {
 // bv functions are not yet available!
 Cursor::Cursor(BufferView & bv)
        : DocIterator(), bv_(&bv), anchor_(), x_target_(-1), textTargetOffset_(0),
-         selection_(false), mark_(false), logicalpos_(false)
+         selection_(false), mark_(false), logicalpos_(false),
+         current_font(inherit_font)
 {}
 
 
@@ -290,9 +294,8 @@ void Cursor::setCursor(DocIterator const & cur)
 
 void Cursor::dispatch(FuncRequest const & cmd0)
 {
-       LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION
-                            << " cmd: " << cmd0 << '\n'
-                            << *this << endl;
+       LYXERR(Debug::DEBUG, BOOST_CURRENT_FUNCTION
+                            << " cmd: " << cmd0 << '\n' << *this);
        if (empty())
                return;
 
@@ -304,8 +307,8 @@ void Cursor::dispatch(FuncRequest const & cmd0)
        getPos(beforeDispX_, beforeDispY_);
        beforeDispatchCursor_ = *this;
        for (; depth(); pop()) {
-               LYXERR(Debug::DEBUG) << "Cursor::dispatch: cmd: "
-                       << cmd0 << endl << *this << endl;
+               LYXERR(Debug::DEBUG, "Cursor::dispatch: cmd: "
+                       << cmd0 << endl << *this);
                BOOST_ASSERT(pos() <= lastpos());
                BOOST_ASSERT(idx() <= lastidx());
                BOOST_ASSERT(pit() <= lastpit());
@@ -323,7 +326,7 @@ void Cursor::dispatch(FuncRequest const & cmd0)
        // it completely to get a 'bomb early' behaviour in case this
        // object will be used again.
        if (!disp_.dispatched()) {
-               LYXERR(Debug::DEBUG) << "RESTORING OLD CURSOR!" << endl;
+               LYXERR(Debug::DEBUG, "RESTORING OLD CURSOR!");
                operator=(safe);
                disp_.update(Update::None);
                disp_.dispatched(false);
@@ -351,8 +354,7 @@ BufferView & Cursor::bv() const
 Buffer & Cursor::buffer() const
 {
        BOOST_ASSERT(bv_);
-       BOOST_ASSERT(bv_->buffer());
-       return *bv_->buffer();
+       return bv_->buffer();
 }
 
 
@@ -369,19 +371,19 @@ void Cursor::push(Inset & p)
 }
 
 
-void Cursor::pushLeft(Inset & p)
+void Cursor::pushBackward(Inset & p)
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Entering inset " << t << " left" << endl;
+       //lyxerr << "Entering inset " << t << " front" << endl;
        push(p);
        p.idxFirst(*this);
 }
 
 
-bool Cursor::popLeft()
+bool Cursor::popBackward()
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Leaving inset to the left" << endl;
+       //lyxerr << "Leaving inset from in front" << endl;
        inset().notifyCursorLeaves(*this);
        if (depth() == 1)
                return false;
@@ -390,10 +392,10 @@ bool Cursor::popLeft()
 }
 
 
-bool Cursor::popRight()
+bool Cursor::popForward()
 {
        BOOST_ASSERT(!empty());
-       //lyxerr << "Leaving inset to the right" << endl;
+       //lyxerr << "Leaving inset from in back" << endl;
        const pos_type lp = (depth() > 1) ? (*this)[depth() - 2].lastpos() : 0;
        inset().notifyCursorLeaves(*this);
        if (depth() == 1)
@@ -418,7 +420,7 @@ int Cursor::currentMode()
 
 void Cursor::getPos(int & x, int & y) const
 {
-       Point p = bv_funcs::getPos(bv(), *this, boundary());
+       Point p = bv().getPos(*this, boundary());
        x = p.x_;
        y = p.y_;
 }
@@ -439,7 +441,7 @@ void Cursor::resetAnchor()
 
 
 
-bool Cursor::posLeft()
+bool Cursor::posBackward()
 {
        if (pos() == 0)
                return false;
@@ -448,7 +450,7 @@ bool Cursor::posLeft()
 }
 
 
-bool Cursor::posRight()
+bool Cursor::posForward()
 {
        if (pos() == lastpos())
                return false;
@@ -674,17 +676,17 @@ bool Cursor::openable(MathAtom const & t) const
        // we can't move into anything new during selection
        if (depth() >= anchor_.depth())
                return false;
-       if (!ptr_cmp(t.nucleus(), &anchor_[depth()].inset()))
+       if (t.nucleus() != &anchor_[depth()].inset())
                return false;
 
        return true;
 }
 
 
-void Cursor::setScreenPos(int x, int y)
+void Cursor::setScreenPos(int x, int /*y*/)
 {
        setTargetX(x);
-       bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight());
+       //bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight());
 }
 
 
@@ -771,10 +773,10 @@ void Cursor::niceInsert(MathAtom const & t)
        plainInsert(t);
        // enter the new inset and move the contents of the selection if possible
        if (t->isActive()) {
-               posLeft();
-               // be careful here: don't use 'pushLeft(t)' as this we need to
+               posBackward();
+               // be careful here: don't use 'pushBackward(t)' as this we need to
                // push the clone, not the original
-               pushLeft(*nextInset());
+               pushBackward(*nextInset());
                // We may not use niceInsert here (recursion)
                MathData ar;
                asArray(safe, ar);
@@ -805,7 +807,7 @@ bool Cursor::backspace()
        if (pos() == 0) {
                // If empty cell, and not part of a big cell
                if (lastpos() == 0 && inset().nargs() == 1) {
-                       popLeft();
+                       popBackward();
                        // Directly delete empty cell: [|[]] => [|]
                        if (inMathed()) {
                                plainErase();
@@ -818,7 +820,7 @@ bool Cursor::backspace()
                        if (inMathed())
                                pullArg();
                        else
-                               popLeft();
+                               popBackward();
                        return true;
                }
        }
@@ -864,7 +866,7 @@ bool Cursor::erase()
        if (pos() == lastpos()) {
                bool one_cell = inset().nargs() == 1;
                if (one_cell && lastpos() == 0) {
-                       popLeft();
+                       popBackward();
                        // Directly delete empty cell: [|[]] => [|]
                        if (inMathed()) {
                                plainErase();
@@ -943,7 +945,13 @@ bool Cursor::macroModeClose()
        InsetMathNest * const in = inset().asInsetMath()->asNestInset();
        if (in && in->interpretString(*this, s))
                return true;
-       plainInsert(createInsetMath(name));
+       MathAtom atom = createInsetMath(name);
+       MathMacro * atomAsMacro = atom.nucleus()->asMacro();
+       if (atomAsMacro) {
+               // make non-greedy, i.e. don't eat parameters from the right
+               atomAsMacro->setDisplayMode(MathMacro::DISPLAY_INTERACTIVE_INIT);
+       }
+       plainInsert(atom);
        return true;
 }
 
@@ -960,8 +968,8 @@ void Cursor::handleNest(MathAtom const & a, int c)
        MathAtom t = a;
        asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c));
        insert(t);
-       posLeft();
-       pushLeft(*nextInset());
+       posBackward();
+       pushBackward(*nextInset());
 }
 
 
@@ -1012,7 +1020,7 @@ void Cursor::pullArg()
 {
        // FIXME: Look here
        MathData ar = cell();
-       if (popLeft() && inMathed()) {
+       if (popBackward() && inMathed()) {
                plainErase();
                cell().insert(pos(), ar);
                resetAnchor();
@@ -1071,7 +1079,7 @@ bool Cursor::upDownInMath(bool up)
        // target
        if (x_target_ == -1)
                setTargetX(xo);
-       else if (inset().asTextInset() && xo - textTargetOffset() != x_target()) {
+       else if (inset().asInsetText() && xo - textTargetOffset() != x_target()) {
                // In text mode inside the line (not left or right) possibly set a new target_x,
                // but only if we are somewhere else than the previous target-offset.
                
@@ -1154,8 +1162,8 @@ bool Cursor::upDownInMath(bool up)
        }
        
        // any improvement going just out of inset?
-       if (popLeft() && inMathed()) {
-               //lyxerr << "updown: popLeft succeeded" << endl;
+       if (popBackward() && inMathed()) {
+               //lyxerr << "updown: popBackward succeeded" << endl;
                int xnew;
                int ynew;
                getPos(xnew, ynew);
@@ -1214,7 +1222,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
                xo = targetX();
                
        // first get the current line
-       TextMetrics const & tm = bv_->textMetrics(text());
+       TextMetrics & tm = bv_->textMetrics(text());
        ParagraphMetrics const & pm = tm.parMetrics(pit());
        int row;
        if (pos() && boundary())
@@ -1234,13 +1242,13 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
 
        // with and without selection are handled differently
        if (!selection()) {
-               int yo = bv_funcs::getPos(bv(), *this, boundary()).y_;
+               int yo = bv().getPos(*this, boundary()).y_;
                Cursor old = *this;
                // To next/previous row
                if (up)
-                       text()->editXY(*this, xo, yo - textRow().ascent() - 1);
+                       tm.editXY(*this, xo, yo - textRow().ascent() - 1);
                else
-                       text()->editXY(*this, xo, yo + textRow().descent() + 1);
+                       tm.editXY(*this, xo, yo + textRow().descent() + 1);
                clearSelection();
                
                // This happens when you move out of an inset.
@@ -1285,7 +1293,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
 
 void Cursor::handleFont(string const & font)
 {
-       LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << ": " << font << endl;
+       LYXERR(Debug::DEBUG, BOOST_CURRENT_FUNCTION << ": " << font);
        docstring safe;
        if (selection()) {
                macroModeClose();
@@ -1296,17 +1304,17 @@ void Cursor::handleFont(string const & font)
                // something left in the cell
                if (pos() == 0) {
                        // cursor in first position
-                       popLeft();
+                       popBackward();
                } else if (pos() == lastpos()) {
                        // cursor in last position
-                       popRight();
+                       popForward();
                } else {
                        // cursor in between. split cell
                        MathData::iterator bt = cell().begin();
                        MathAtom at = createInsetMath(from_utf8(font));
                        at.nucleus()->cell(0) = MathData(bt, bt + pos());
                        cell().erase(bt, bt + pos());
-                       popLeft();
+                       popBackward();
                        plainInsert(at);
                }
        } else {
@@ -1336,7 +1344,7 @@ docstring Cursor::selectionAsString(bool label) const
                return docstring();
 
        if (inTexted()) {
-               Buffer const & buffer = *bv().buffer();
+               Buffer const & buffer = bv().buffer();
                ParagraphList const & pars = text()->paragraphs();
 
                // should be const ...
@@ -1398,8 +1406,6 @@ Encoding const * Cursor::getEncoding() const
 {
        if (empty())
                return 0;
-       if (!bv().buffer())
-               return 0;
        int s = 0;
        // go up until first non-0 text is hit
        // (innermost text is 0 in mathed)
@@ -1409,7 +1415,7 @@ Encoding const * Cursor::getEncoding() const
        CursorSlice const & sl = operator[](s);
        Text const & text = *sl.text();
        Font font = text.getPar(sl.pit()).getFont(
-               bv().buffer()->params(), sl.pos(), outerFont(sl.pit(), text.paragraphs()));
+               bv().buffer().params(), sl.pos(), outerFont(sl.pit(), text.paragraphs()));
        return font.language()->encoding();
 }
 
@@ -1440,7 +1446,7 @@ void Cursor::noUpdate()
 
 Font Cursor::getFont() const
 {
-       // The logic here should more or less match to the Text::setCurrentFont
+       // 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.
        
@@ -1462,14 +1468,15 @@ Font Cursor::getFont() const
        
        // on space? Take the font before (only for RTL boundary stay)
        if (pos > 0) {
+               TextMetrics const & tm = bv().textMetrics(&text);
                if (pos == sl.lastpos()
-                               || (par.isSeparator(pos) &&
-                                               !text.isRTLBoundary(buffer(), par, pos)))
+                       || (par.isSeparator(pos) 
+                       && !tm.isRTLBoundary(sl.pit(), pos)))
                        --pos;
        }
        
        // get font at the position
-       Font font = par.getFont(bv().buffer()->params(), pos,
+       Font font = par.getFont(bv().buffer().params(), pos,
                outerFont(sl.pit(), text.paragraphs()));
 
        return font;
@@ -1507,4 +1514,123 @@ bool notifyCursorLeaves(DocIterator const & old, Cursor & cur)
 }
 
 
+void Cursor::setCurrentFont()
+{
+       CursorSlice const & cs = innerTextSlice();
+       Paragraph const & par = cs.paragraph();
+       pos_type cpit = cs.pit();
+       pos_type cpos = cs.pos();
+       Text const & ctext = *cs.text();
+       TextMetrics const & tm = bv().textMetrics(&ctext);
+
+       // are we behind previous char in fact? -> go to that char
+       if (cpos > 0 && boundary())
+               --cpos;
+
+       // find position to take the font from
+       if (cpos != 0) {
+               // paragraph end? -> font of last char
+               if (cpos == lastpos())
+                       --cpos;
+               // on space? -> look at the words in front of space
+               else if (cpos > 0 && par.isSeparator(cpos))     {
+                       // abc| def -> font of c
+                       // abc |[WERBEH], i.e. boundary==true -> font of c
+                       // abc [WERBEH]| def, font of the space
+                       if (!tm.isRTLBoundary(cpit, cpos))
+                               --cpos;
+               }
+       }
+
+       // get font
+       BufferParams const & bufparams = buffer().params();
+       current_font = par.getFontSettings(bufparams, cpos);
+       real_current_font = tm.getDisplayFont(cpit, cpos);
+
+       // special case for paragraph end
+       if (cs.pos() == lastpos()
+           && tm.isRTLBoundary(cpit, cs.pos())
+           && !boundary()) {
+               Language const * lang = par.getParLanguage(bufparams);
+               current_font.setLanguage(lang);
+               current_font.fontInfo().setNumber(FONT_OFF);
+               real_current_font.setLanguage(lang);
+               real_current_font.fontInfo().setNumber(FONT_OFF);
+       }
+}
+
+
+bool Cursor::textUndo()
+{
+       DocIterator dit = *this;
+       // Undo::textUndo() will modify dit.
+       if (!bv_->buffer().undo().textUndo(dit))
+               return false;
+       // Set cursor
+       setCursor(dit);
+       selection() = false;
+       resetAnchor();
+       fixIfBroken();
+       return true;
+}
+
+
+bool Cursor::textRedo()
+{
+       DocIterator dit = *this;
+       // Undo::textRedo() will modify dit.
+       if (!bv_->buffer().undo().textRedo(dit))
+               return false;
+       // Set cursor
+       setCursor(dit);
+       selection() = false;
+       resetAnchor();
+       fixIfBroken();
+       return true;
+}
+
+
+void Cursor::finishUndo()
+{
+       bv_->buffer().undo().finishUndo();
+}
+
+
+void Cursor::recordUndo(UndoKind kind, pit_type from, pit_type to)
+{
+       bv_->buffer().undo().recordUndo(*this, kind, from, to);
+}
+
+
+void Cursor::recordUndo(UndoKind kind, pit_type from)
+{
+       bv_->buffer().undo().recordUndo(*this, kind, from);
+}
+
+
+void Cursor::recordUndo(UndoKind kind)
+{
+       bv_->buffer().undo().recordUndo(*this, kind);
+}
+
+
+void Cursor::recordUndoInset(UndoKind kind)
+{
+       bv_->buffer().undo().recordUndoInset(*this, kind);
+}
+
+
+void Cursor::recordUndoFullDocument()
+{
+       bv_->buffer().undo().recordUndoFullDocument(*this);
+}
+
+
+void Cursor::recordUndoSelection()
+{
+       bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO,
+               selBegin().pit(), selEnd().pit());
+}
+
+
 } // namespace lyx