]> git.lyx.org Git - lyx.git/blobdiff - src/Cursor.cpp
Fulfill promise to Andre: TextClass_ptr --> TextClassPtr.
[lyx.git] / src / Cursor.cpp
index b3bdadeb6cf3cbe65ba4500a0e550481dfa16253..60598573d6432c6f4cebbbb1914f311a180b6a42 100644 (file)
 #include <limits>
 #include <map>
 
-namespace lyx {
-
 using std::string;
 using std::vector;
 using std::endl;
 using std::min;
 using std::for_each;
 
+
+namespace lyx {
+
 namespace {
 
        bool
@@ -131,6 +132,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)
@@ -185,6 +187,7 @@ namespace {
 
                return false;
        }
+       */
 
 
        /// moves position closest to (x, y) in given box
@@ -205,7 +208,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);
@@ -265,7 +268,7 @@ 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(Font::ALL_INHERIT)
 {}
 
 
@@ -301,8 +304,7 @@ void Cursor::dispatch(FuncRequest const & cmd0)
        
        // store some values to be used inside of the handlers
        getPos(beforeDispX_, beforeDispY_);
-       beforeDispDepth_ = depth();
-       
+       beforeDispatchCursor_ = *this;
        for (; depth(); pop()) {
                LYXERR(Debug::DEBUG) << "Cursor::dispatch: cmd: "
                        << cmd0 << endl << *this << endl;
@@ -319,6 +321,7 @@ void Cursor::dispatch(FuncRequest const & cmd0)
                if (disp_.dispatched())
                        break;
        }
+       
        // it completely to get a 'bomb early' behaviour in case this
        // object will be used again.
        if (!disp_.dispatched()) {
@@ -326,6 +329,10 @@ void Cursor::dispatch(FuncRequest const & cmd0)
                operator=(safe);
                disp_.update(Update::None);
                disp_.dispatched(false);
+       } else {
+               // restore the previous one because nested Cursor::dispatch calls
+               // are possible which would change it
+               beforeDispatchCursor_ = safe.beforeDispatchCursor_;
        }
 }
 
@@ -346,8 +353,7 @@ BufferView & Cursor::bv() const
 Buffer & Cursor::buffer() const
 {
        BOOST_ASSERT(bv_);
-       BOOST_ASSERT(bv_->buffer());
-       return *bv_->buffer();
+       return bv_->buffer();
 }
 
 
@@ -507,9 +513,7 @@ void Cursor::setSelection()
 {
        selection() = true;
        // A selection with no contents is not a selection
-#ifdef WITH_WARNINGS
-#warning doesnt look ok
-#endif
+       // FIXME: doesnt look ok
        if (pit() == anchor().pit() && pos() == anchor().pos())
                selection() = false;
 }
@@ -584,9 +588,11 @@ bool Cursor::selHandle(bool sel)
        if (sel == selection())
                return false;
 
+       if (!sel)
+               cap::saveSelection(*this);
+
        resetAnchor();
        selection() = sel;
-       cap::saveSelection(*this);
        return true;
 }
 
@@ -676,10 +682,10 @@ bool Cursor::openable(MathAtom const & t) const
 }
 
 
-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());
 }
 
 
@@ -1005,9 +1011,7 @@ InsetMathUnknown * Cursor::activeMacro()
 
 void Cursor::pullArg()
 {
-#ifdef WITH_WARNINGS
-#warning Look here
-#endif
+       // FIXME: Look here
        MathData ar = cell();
        if (popLeft() && inMathed()) {
                plainErase();
@@ -1021,9 +1025,7 @@ void Cursor::pullArg()
 
 void Cursor::touch()
 {
-#ifdef WITH_WARNINGS
-#warning look here
-#endif
+       // FIXME: look here
 #if 0
        DocIterator::const_iterator it = begin();
        DocIterator::const_iterator et = end();
@@ -1076,7 +1078,7 @@ bool Cursor::upDownInMath(bool up)
                
                // We want to keep the x-target on subsequent up/down movements
                // that cross beyond the end of short lines. Thus a special
-               // handling when the cursor is at the end of line: Use the new 
+               // handling when the cursor is at the end of line: Use the new
                // x-target only if the old one was before the end of line
                // or the old one was after the beginning of the line
                bool inRTL = isWithinRtlParagraph(*this);
@@ -1090,12 +1092,12 @@ bool Cursor::upDownInMath(bool up)
                        right = pos() == textRow().endpos();
                }
                if ((!left && !right) ||
-                               (left && !right && xo < x_target_) || 
+                               (left && !right && xo < x_target_) ||
                                (!left && right && x_target_ < xo))
                        setTargetX(xo);
                else
                        xo = targetX();
-       } else 
+       } else
                xo = targetX();
 
        // try neigbouring script insets
@@ -1168,7 +1170,7 @@ bool Cursor::upDownInMath(bool up)
 }
 
 
-bool Cursor::upDownInText(bool up
+bool Cursor::upDownInText(bool up, bool & updateNeeded)
 {
        BOOST_ASSERT(text());
 
@@ -1183,13 +1185,14 @@ bool Cursor::upDownInText(bool up)
        // if we cannot move up/down inside this inset anymore
        if (x_target_ == -1)
                setTargetX(xo);
-       else if (xo - textTargetOffset() != x_target() && depth() == beforeDispDepth_) {
+       else if (xo - textTargetOffset() != x_target() &&
+                                        depth() == beforeDispatchCursor_.depth()) {
                // 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.
                
                // We want to keep the x-target on subsequent up/down movements
                // that cross beyond the end of short lines. Thus a special
-               // handling when the cursor is at the end of line: Use the new 
+               // handling when the cursor is at the end of line: Use the new
                // x-target only if the old one was before the end of line
                // or the old one was after the beginning of the line
                bool inRTL = isWithinRtlParagraph(*this);
@@ -1203,16 +1206,16 @@ bool Cursor::upDownInText(bool up)
                        right = pos() == textRow().endpos();
                }
                if ((!left && !right) ||
-                               (left && !right && xo < x_target_) || 
+                               (left && !right && xo < x_target_) ||
                                (!left && right && x_target_ < xo))
                        setTargetX(xo);
                else
                        xo = targetX();
-       } else 
+       } else
                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())
@@ -1225,20 +1228,20 @@ bool Cursor::upDownInText(bool up)
                if (pit() == 0 && row == 0)
                        return false;
        } else {
-               if (pit() + 1 >= int(text()->paragraphs().size()) && 
+               if (pit() + 1 >= int(text()->paragraphs().size()) &&
                                row + 1 >= int(pm.rows().size()))
                        return false;
        }       
-       
+
        // with and without selection are handled differently
        if (!selection()) {
                int yo = bv_funcs::getPos(bv(), *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.
@@ -1248,12 +1251,11 @@ bool Cursor::upDownInText(bool up)
                Cursor dummy = *this;
                if (dummy == old)
                        ++dummy.pos();
-               
-               bool const changed = bv().checkDepm(dummy, old);
-               
-               // Make sure that cur gets back whatever happened to dummy(Lgb)
-               if (changed)
+               if (bv().checkDepm(dummy, old)) {
+                       updateNeeded = true;
+                       // Make sure that cur gets back whatever happened to dummy(Lgb)
                        operator=(dummy);
+               }
        } else {
                // if there is a selection, we stay out of any inset, and just jump to the right position:
                Cursor old = *this;
@@ -1273,10 +1275,10 @@ bool Cursor::upDownInText(bool up)
                                top().pos() = std::min(tm.x2pos(pit(), 0, xo), top().lastpos());
                        }
                }
-               
-               bv().checkDepm(*this, old);
+
+               updateNeeded |= bv().checkDepm(*this, old);
        }
-       
+
        updateTextTargetOffset();
        return true;
 }      
@@ -1335,7 +1337,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 ...
@@ -1397,8 +1399,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)
@@ -1408,7 +1408,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();
 }
 
@@ -1439,31 +1439,117 @@ void Cursor::noUpdate()
 
 Font Cursor::getFont() const
 {
+       // 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.
+       
        // HACK. far from being perfect...
-       int s = 0;
        // go up until first non-0 text is hit
        // (innermost text is 0 in mathed)
+       int s = 0;
        for (s = depth() - 1; s >= 0; --s)
                if (operator[](s).text())
                        break;
        CursorSlice const & sl = operator[](s);
        Text const & text = *sl.text();
-       Font font = text.getPar(sl.pit()).getFont(
-               bv().buffer()->params(),
-               sl.pos(),
+       Paragraph const & par = text.getPar(sl.pit());
+       
+       // on boundary, so we are really at the character before
+       pos_type pos = sl.pos();
+       if (pos > 0 && boundary())
+               --pos;
+       
+       // 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) 
+                       && !tm.isRTLBoundary(sl.pit(), pos)))
+                       --pos;
+       }
+       
+       // get font at the position
+       Font font = par.getFont(bv().buffer().params(), pos,
                outerFont(sl.pit(), text.paragraphs()));
 
        return font;
 }
 
 
-void Cursor::fixIfBroken()
+bool Cursor::fixIfBroken()
 {
        if (DocIterator::fixIfBroken()) {
                        clearSelection();
                        resetAnchor();
+                       return true;
+       }
+       return false;
+}
+
+
+bool notifyCursorLeaves(DocIterator const & old, Cursor & cur)
+{
+       // find inset in common
+       size_type i;
+       for (i = 0; i < old.depth() && i < cur.depth(); ++i) {
+               if (&old.inset() != &cur.inset())
+                       break;
+       }
+       
+       // notify everything on top of the common part in old cursor,
+       // but stop if the inset claims the cursor to be invalid now
+       for (;  i < old.depth(); ++i) {
+               if (old[i].inset().notifyCursorLeaves(cur))
+                       return true;
        }
+       
+       return false;
 }
 
 
+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.setNumber(Font::OFF);
+               real_current_font.setLanguage(lang);
+               real_current_font.setNumber(Font::OFF);
+       }
+}
+
 } // namespace lyx