]> git.lyx.org Git - features.git/blobdiff - src/TextMetrics.cpp
New helper method Row::Element::isRTL()
[features.git] / src / TextMetrics.cpp
index 2119f8ed16037416359c9792d3187e8878516310..fc5e1c5ac5ec0e29856bcfcf7738150487749f03 100644 (file)
@@ -58,28 +58,6 @@ using frontend::FontMetrics;
 
 namespace {
 
-int numberOfSeparators(Row const & row)
-{
-       int n = 0;
-       Row::const_iterator cit = row.begin();
-       Row::const_iterator const end = row.end();
-       for ( ; cit != end ; ++cit)
-               if (cit->type == Row::SEPARATOR)
-                       ++n;
-       return n;
-}
-
-
-void setSeparatorWidth(Row & row, double w)
-{
-       row.separator = w;
-       Row::iterator it = row.begin();
-       Row::iterator const end = row.end();
-       for ( ; it != end ; ++it)
-               if (it->type == Row::SEPARATOR)
-                       it->extra = w;
-}
-
 
 int numberOfLabelHfills(Paragraph const & par, Row const & row)
 {
@@ -385,7 +363,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                Cursor & cur = const_cast<Cursor &>(bv_->cursor());
                // In some cases, we do not know how to record undo
                if (&cur.inset() == &text_->inset())
-                       cur.recordUndo(ATOMIC_UNDO, pit, pit);
+                       cur.recordUndo(pit, pit);
 
                int const moveCursor = par.fixBiblio(buffer);
 
@@ -446,7 +424,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                MacroContext mc(&buffer, parPos);
                MetricsInfo mi(bv_, font.fontInfo(), w, mc);
                ii->inset->metrics(mi, dim);
-               Dimension const old_dim = pm.insetDimension(ii->inset);
+               Dimension const old_dim = pm.insetDimension(ii->inset);
                if (old_dim != dim) {
                        pm.setInsetDimension(ii->inset, dim);
                        changed = true;
@@ -569,12 +547,6 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
        // FIXME: put back this assertion when the crash on new doc is solved.
        //LASSERT(w >= 0, /**/);
 
-       bool const is_rtl = text_->isRTL(par);
-       if (is_rtl)
-               row.left_margin = rightMargin(pit);
-       else
-               row.left_margin = leftMargin(max_width_, pit, row.pos());
-
        // is there a manual margin with a manual label
        Layout const & layout = par.layout();
 
@@ -609,15 +581,15 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                // set x how you need it
                switch (getAlign(par, row.pos())) {
                case LYX_ALIGN_BLOCK: {
-                       int const ns = numberOfSeparators(row);
+                       int const ns = row.countSeparators();
                        /** If we have separators, and this row has
                         * not be broken abruptly by a display inset
                         * or newline, then stretch it */
                        if (ns && !row.right_boundary()
                            && row.endpos() != par.size()) {
-                               setSeparatorWidth(row, double(w) / ns);
+                               row.setSeparatorExtraWidth(double(w) / ns);
                                row.dimension().wid = width;
-                       } else if (is_rtl) {
+                       } else if (text_->isRTL(par)) {
                                row.dimension().wid = width;
                                row.left_margin += w;
                        }
@@ -625,6 +597,7 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                }
                case LYX_ALIGN_RIGHT:
                        row.left_margin += w;
+                       row.dimension().wid += w;
                        break;
                case LYX_ALIGN_CENTER:
                        row.dimension().wid = width - w / 2;
@@ -777,20 +750,26 @@ private:
 
 /** This is the function where the hard work is done. The code here is
  * very sensitive to small changes :) Note that part of the
- * intelligence is also in Row::shorten_if_needed
+ * intelligence is also in Row::shortenIfNeeded.
  */
 void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit) const
 {
        Paragraph const & par = text_->getPar(pit);
        pos_type const end = par.size();
        pos_type const pos = row.pos();
-       int const width = max_width_ - right_margin;
        pos_type const body_pos = par.beginOfBody();
+       bool const is_rtl = text_->isRTL(par);
+
        row.clear();
-       // This make get changed in computeRowMetrics depending on RTL
        row.left_margin = leftMargin(max_width_, pit, pos);
-       row.dimension().wid = row.left_margin;
        row.right_margin = right_margin;
+       if (is_rtl)
+               swap(row.left_margin, row.right_margin);
+       // Remember that the row width takes into account the left_margin
+       // but not the right_margin.
+       row.dimension().wid = row.left_margin;
+       // the width available for the row.
+       int const width = max_width_ - row.right_margin;
 
        if (pos >= end || row.width() > width) {
                row.endpos(end);
@@ -809,20 +788,16 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
 #endif
 
        // check for possible inline completion
-       DocIterator const & inlineCompletionPos = bv_->inlineCompletionPos();
-       pos_type inlineCompletionLPos = -1;
-       if (inlineCompletionPos.inTexted()
-           && inlineCompletionPos.text() == text_
-           && inlineCompletionPos.pit() == pit) {
-               // draw logically behind the previous character
-               inlineCompletionLPos = inlineCompletionPos.pos() - 1;
-       }
+       DocIterator const & ic_it = bv_->inlineCompletionPos();
+       pos_type ic_pos = -1;
+       if (ic_it.inTexted() && ic_it.text() == text_ && ic_it.pit() == pit)
+               ic_pos = ic_it.pos();
 
        // Now we iterate through until we reach the right margin
        // or the end of the par, then build a representation of the row.
        pos_type i = pos;
        FontIterator fi = FontIterator(*this, par, pit, pos);
-       while (i < end && row.width() < width) {
+       while (i < end && row.width() <= width) {
                char_type c = par.getChar(i);
                // The most special cases are handled first.
                if (par.isInset(i)) {
@@ -840,13 +815,6 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
                        int const add = max(fm.width(par.layout().labelsep),
                                            labelEnd(pit) - row.width());
                        row.addSpace(i, add, *fi, par.lookupChange(i));
-               } else if (par.isLineSeparator(i)) {
-                       // In theory, no inset has this property. If
-                       // this is done, a new addSeparator which
-                       // takes an inset as parameter should be
-                       // added.
-                       LATTEST(!par.isInset(i));
-                       row.addSeparator(i, c, *fi, par.lookupChange(i));
                } else if (c == '\t')
                        row.addSpace(i, theFontMetrics(*fi).width(from_ascii("    ")),
                                     *fi, par.lookupChange(i));
@@ -854,12 +822,18 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
                        row.add(i, c, *fi, par.lookupChange(i));
 
                // add inline completion width
-               if (inlineCompletionLPos == i &&
-                   !bv_->inlineCompletion().empty()) {
+               // draw logically behind the previous character
+               if (ic_pos == i + 1 && !bv_->inlineCompletion().empty()) {
+                       docstring const comp = bv_->inlineCompletion();
+                       size_t const uniqueTo =bv_->inlineCompletionUniqueChars();
                        Font f = *fi;
-                       f.fontInfo().setColor(Color_inlinecompletion);
-                       row.addVirtual(i + 1, bv_->inlineCompletion(),
-                                         f, Change());
+
+                       if (uniqueTo > 0) {
+                               f.fontInfo().setColor(Color_inlinecompletion);
+                               row.addVirtual(i + 1, comp.substr(0, uniqueTo), f, Change());
+                       }
+                       f.fontInfo().setColor(Color_nonunique_inlinecompletion);
+                       row.addVirtual(i + 1, comp.substr(uniqueTo), f, Change());
                }
 
                // Handle some situations that abruptly terminate the row
@@ -900,14 +874,9 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
        // if the row is too large, try to cut at last separator.
        row.shortenIfNeeded(body_pos, width);
 
-       // if the row ends with a separator that is not at end of
-       // paragraph, remove it
-       if (!row.empty() && row.back().type == Row::SEPARATOR
-           && row.endpos() < par.size())
-               row.pop_back();
-
        // make sure that the RTL elements are in reverse ordering
-       row.reverseRTL(text_->isRTL(par));
+       row.reverseRTL(is_rtl);
+       //LYXERR0("breakrow: row is " << row);
 }
 
 
@@ -1093,6 +1062,7 @@ void TextMetrics::setRowHeight(Row & row, pit_type const pit,
 pos_type TextMetrics::getPosNearX(Row const & row, int & x,
                                  bool & boundary) const
 {
+       //LYXERR0("getPosNearX(" << x << ") row=" << row);
        /// For the main Text, it is possible that this pit is not
        /// yet in the CoordCache when moving cursor up.
        /// x Paragraph coordinate is always 0 for main text anyway.
@@ -1133,7 +1103,7 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
                 */
                else if (pos == cit->endpos
                         && cit + 1 != row.end()
-                        && cit->font.isVisibleRightToLeft() != (cit + 1)->font.isVisibleRightToLeft())
+                        && cit->isRTL() != (cit + 1)->isRTL())
                        boundary = true;
        }
 
@@ -1148,6 +1118,7 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
                boundary = true;
 
        x += xo;
+       //LYXERR0("getPosNearX ==> pos=" << pos << ", boundary=" << boundary);
        return pos;
 }
 
@@ -1616,12 +1587,16 @@ int TextMetrics::leftMargin(int max_width,
        l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
                tclass.leftmargin());
 
-       if (par.getDepth() != 0) {
+       int depth = par.getDepth();
+       if (depth != 0) {
                // find the next level paragraph
                pit_type newpar = text_->outerHook(pit);
                if (newpar != pit_type(pars.size())) {
                        if (pars[newpar].layout().isEnvironment()) {
-                               l_margin = leftMargin(max_width, newpar);
+                               int nestmargin = depth * nestMargin();
+                               if (text_->isMainText())
+                                       nestmargin += changebarMargin();
+                               l_margin = max(leftMargin(max_width, newpar), nestmargin);
                                // Remove the parindent that has been added
                                // if the paragraph was empty.
                                if (pars[newpar].empty() &&
@@ -1736,7 +1711,7 @@ int TextMetrics::leftMargin(int max_width,
        }
 
        if (!par.params().leftIndent().zero())
-               l_margin += par.params().leftIndent().inPixels(max_width);
+               l_margin += par.params().leftIndent().inPixels(max_width, labelfont_metrics.em());
 
        LyXAlignment align;
 
@@ -1884,7 +1859,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
                        || rowSlice == bv_->lastRowSlice();
 
                // Take this opportunity to spellcheck the row contents.
-               if (row_has_changed && lyxrc.spellcheck_continuously) {
+               if (row_has_changed && pi.do_spellcheck && lyxrc.spellcheck_continuously) {
                        text_->getPar(pit).spellCheck();
                }