]> git.lyx.org Git - lyx.git/blobdiff - src/rowpainter.cpp
Fixed some lines that were too long. It compiled afterwards.
[lyx.git] / src / rowpainter.cpp
index 182bc10a6a71815dea98c5dabba225dd3ba31fa1..d9e41253e62d56983d1f73525f8b93d3a5699c6d 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "rowpainter.h"
 
+#include "Bidi.h"
 #include "Buffer.h"
 #include "CoordCache.h"
 #include "Cursor.h"
@@ -65,8 +66,8 @@ bool refreshInside;
 class RowPainter {
 public:
        /// initialise and run painter
-       RowPainter(PainterInfo & pi, LyXText const & text,
-               pit_type pit, Row const & row, int x, int y);
+       RowPainter(PainterInfo & pi, Text const & text,
+               pit_type pit, Row const & row, Bidi & bidi, int x, int y);
 
        // paint various parts
        void paintAppendix();
@@ -99,8 +100,8 @@ private:
        /// Painter to use
        Painter & pain_;
 
-       /// LyXText for the row
-       LyXText const & text_;
+       /// Text for the row
+       Text const & text_;
        TextMetrics & text_metrics_;
        ParagraphList const & pars_;
 
@@ -113,6 +114,11 @@ private:
        ParagraphMetrics const & pm_;
        int max_width_;
 
+       /// bidi cache, comes from outside the rowpainter because
+       /// rowpainters are normally created in a for loop and there only
+       /// one of them is active at a time.
+       Bidi & bidi_;
+
        /// is row erased? (change tracking)
        bool erased_;
 
@@ -128,17 +134,18 @@ private:
 
 
 RowPainter::RowPainter(PainterInfo & pi,
-       LyXText const & text, pit_type pit, Row const & row, int x, int y)
+       Text const & text, pit_type pit, Row const & row, Bidi & bidi, int x, int y)
        : bv_(*pi.base.bv), pain_(pi.pain), text_(text),
          text_metrics_(pi.base.bv->textMetrics(&text)),
          pars_(text.paragraphs()),
          row_(row), pit_(pit), par_(text.paragraphs()[pit]),
          pm_(text_metrics_.parMetrics(pit)),
          max_width_(bv_.workWidth()),
-         erased_(pi.erased_),
+               bidi_(bidi), erased_(pi.erased_),
          xo_(x), yo_(y), width_(text_metrics_.width())
 {
        RowMetrics m = text_metrics_.computeRowMetrics(pit_, row_);
+       bidi_.computeTables(par_, *bv_.buffer(), row_);
        x_ = m.x + xo_;
 
        //lyxerr << "RowPainter: x: " << x_ << " xo: " << xo_ << " yo: " << yo_ << endl;
@@ -180,7 +187,7 @@ void RowPainter::paintInset(pos_type const pos, Font const & font)
        pi.base.font = inset->noFontChange() ?
                bv_.buffer()->params().getFont() :
                font;
-       pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0);
+       pi.ltr_pos = (bidi_.level(pos) % 2 == 0);
        pi.erased_ = erased_ || par_.isDeleted(pos);
 #ifdef DEBUG_METRICS
        int const x1 = int(x_);
@@ -205,15 +212,15 @@ void RowPainter::paintInset(pos_type const pos, Font const & font)
        int const w = max_witdh_ - leftMargin() - right_margin;
        MetricsInfo mi(&bv_, font, w);
        inset->metrics(mi, dim);
-       if (inset->width() > dim.wid) 
+       if (inset->width() > dim.wid)
                lyxerr << "Error: inset " << to_ascii(inset->getInsetName())
                       << " draw width " << inset->width()
                       << "> metrics width " << dim.wid << "." << std::endl;
-       if (inset->ascent() > dim.asc) 
+       if (inset->ascent() > dim.asc)
                lyxerr << "Error: inset " << to_ascii(inset->getInsetName())
                       << " draw ascent " << inset->ascent()
                       << "> metrics ascent " << dim.asc << "." << std::endl;
-       if (inset->descent() > dim.des) 
+       if (inset->descent() > dim.des)
                lyxerr << "Error: inset " << to_ascii(inset->getInsetName())
                       << " draw ascent " << inset->descent()
                       << "> metrics descent " << dim.des << "." << std::endl;
@@ -233,7 +240,7 @@ void RowPainter::paintInset(pos_type const pos, Font const & font)
 
 void RowPainter::paintHebrewComposeChar(pos_type & vpos, Font const & font)
 {
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
 
        docstring str;
 
@@ -267,7 +274,7 @@ void RowPainter::paintHebrewComposeChar(pos_type & vpos, Font const & font)
 
 void RowPainter::paintArabicComposeChar(pos_type & vpos, Font const & font)
 {
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
        docstring str;
 
        // first char
@@ -299,7 +306,7 @@ void RowPainter::paintChars(pos_type & vpos, Font const & font,
                            bool hebrew, bool arabic)
 {
        // This method takes up 70% of time when typing
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
        pos_type const end = row_.endpos();
        FontSpan const font_span = par_.fontSpan(pos);
        Change::Type const prev_change = par_.lookupChange(pos).type;
@@ -311,12 +318,16 @@ void RowPainter::paintChars(pos_type & vpos, Font const & font,
 
        if (arabic) {
                char_type c = str[0];
+               if (c == '(')
+                       c = ')';
+               else if (c == ')')
+                       c = '(';
                str[0] = par_.transformChar(c, pos);
        }
 
        // collect as much similar chars as we can
        for (++vpos ; vpos < end ; ++vpos) {
-               pos = text_.bidi.vis2log(vpos);
+               pos = bidi_.vis2log(vpos);
                if (pos < font_span.first || pos > font_span.last)
                        break;
 
@@ -337,7 +348,7 @@ void RowPainter::paintChars(pos_type & vpos, Font const & font,
                 * Arabic characters, but rather paint them one at a time.
                 * See also http://thread.gmane.org/gmane.editors.lyx.devel/79740
                 */
-               if (hebrew) 
+               if (hebrew)
                        break;
 
                /* FIXME: these checks are irrelevant, since 'arabic' and
@@ -355,6 +366,10 @@ void RowPainter::paintChars(pos_type & vpos, Font const & font,
                */
 
                if (arabic) {
+                       if (c == '(')
+                               c = ')';
+                       else if (c == ')')
+                               c = '(';
                        c = par_.transformChar(c, pos);
                        /* see comment in hebrew, explaining why we break */
                        break;
@@ -368,9 +383,9 @@ void RowPainter::paintChars(pos_type & vpos, Font const & font,
        if (prev_change != Change::UNCHANGED) {
                Font copy(font);
                if (prev_change == Change::DELETED) {
-                       copy.setColor(Color::strikeout);
+                       copy.setColor(Color::deletedtext);
                } else if (prev_change == Change::INSERTED) {
-                       copy.setColor(Color::newtext);
+                       copy.setColor(Color::addedtext);
                }
                x_ += pain_.text(int(x_), yo_, s, copy);
        } else {
@@ -395,7 +410,7 @@ void RowPainter::paintForeignMark(double orig_x, Font const & font, int desc)
 
 void RowPainter::paintFromPos(pos_type & vpos)
 {
-       pos_type const pos = text_.bidi.vis2log(vpos);
+       pos_type const pos = bidi_.vis2log(vpos);
        Font orig_font = text_.getFont(*bv_.buffer(), par_, pos);
 
        double const orig_x = x_;
@@ -414,7 +429,8 @@ void RowPainter::paintFromPos(pos_type & vpos)
        // special case languages
        std::string const & lang = orig_font.language()->lang();
        bool const hebrew = lang == "hebrew";
-       bool const arabic = lang == "arabic";
+       bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi" || 
+                                               lang == "farsi";
 
        // draw as many chars as we can
        if ((!hebrew && !arabic)
@@ -455,7 +471,8 @@ void RowPainter::paintChangeBar()
 
 void RowPainter::paintAppendix()
 {
-       if (!par_.params().appendix())
+       // only draw the appendix frame once (for the main text)
+       if (!par_.params().appendix() || !text_.isMainText(*bv_.buffer()))
                return;
 
        int y = yo_ - row_.ascent();
@@ -548,7 +565,7 @@ void RowPainter::paintFirst()
 
        Buffer const & buffer = *bv_.buffer();
 
-       LyXLayout_ptr const & layout = par_.layout();
+       Layout_ptr const & layout = par_.layout();
 
        if (buffer.params().paragraph_separation == BufferParams::PARSEP_SKIP) {
                if (pit_ != 0) {
@@ -556,7 +573,7 @@ void RowPainter::paintFirst()
                                && !par_.getDepth()) {
                                y_top += buffer.params().getDefSkip().inPixels(bv_);
                        } else {
-                               LyXLayout_ptr const & playout = pars_[pit_ - 1].layout();
+                               Layout_ptr const & playout = pars_[pit_ - 1].layout();
                                if (playout->latextype == LATEX_PARAGRAPH
                                        && !pars_[pit_ - 1].getDepth()) {
                                        // is it right to use defskip here, too? (AS)
@@ -669,12 +686,12 @@ void RowPainter::paintLast()
        if (par_.isInserted(par_.size()) || par_.isDeleted(par_.size())) {
                FontMetrics const & fm = theFontMetrics(bv_.buffer()->params().getFont());
                int const length = fm.maxAscent() / 2;
-               Color::color col = par_.isInserted(par_.size()) ? Color::newtext : Color::strikeout;
-               
+               Color::color col = par_.isInserted(par_.size()) ? Color::addedtext : Color::deletedtext;
+
                pain_.line(int(x_) + 1, yo_ + 2, int(x_) + 1, yo_ + 2 - length, col,
-                          Painter::line_solid, Painter::line_thick);
+                          Painter::line_solid, Painter::line_thick);
                pain_.line(int(x_) + 1 - length, yo_ + 2, int(x_) + 1, yo_ + 2, col,
-                          Painter::line_solid, Painter::line_thick);
+                          Painter::line_solid, Painter::line_thick);
        }
 
        // draw an endlabel
@@ -718,13 +735,19 @@ void RowPainter::paintLast()
 void RowPainter::paintText()
 {
        pos_type const end = row_.endpos();
+       // Spaces at logical line breaks in bidi text must be skipped during 
+       // painting. However, they may appear visually in the middle
+       // of a row; they must be skipped, wherever they are...
+       // * logically "abc_[HEBREW_\nHEBREW]"
+       // * visually "abc_[_WERBEH\nWERBEH]"
+       pos_type skipped_sep_vpos = -1;
        pos_type body_pos = par_.beginOfBody();
        if (body_pos > 0 &&
                (body_pos > end || !par_.isLineSeparator(body_pos - 1))) {
                body_pos = 0;
        }
 
-       LyXLayout_ptr const & layout = par_.layout();
+       Layout_ptr const & layout = par_.layout();
 
        bool running_strikeout = false;
        bool is_struckout = false;
@@ -735,11 +758,22 @@ void RowPainter::paintText()
        Font font;
        Buffer const & buffer = *bv_.buffer();
 
+       // If the last logical character is a separator, don't paint it, unless
+       // it's in the last row of a paragraph; see skipped_sep_vpos declaration
+       if (end > 0 && end < par_.size() && par_.isSeparator(end - 1))
+               skipped_sep_vpos = bidi_.log2vis(end - 1);
+       
        for (pos_type vpos = row_.pos(); vpos < end; ) {
                if (x_ > bv_.workWidth())
                        break;
 
-               pos_type const pos = text_.bidi.vis2log(vpos);
+               // Skip the separator at the logical end of the row
+               if (vpos == skipped_sep_vpos) {
+                       ++vpos;
+                       continue;
+               }
+
+               pos_type const pos = bidi_.vis2log(vpos);
 
                if (pos >= par_.size()) {
                        ++vpos;
@@ -775,11 +809,11 @@ void RowPainter::paintText()
                // We also don't paint across things like tables
                if (running_strikeout && (highly_editable_inset || !is_struckout)) {
                        // Calculate 1/3 height of the buffer's default font
-                       FontMetrics const & fm 
+                       FontMetrics const & fm
                                = theFontMetrics(bv_.buffer()->params().getFont());
                        int const middle = yo_ - fm.maxAscent() / 3;
                        pain_.line(last_strikeout_x, middle, int(x_), middle,
-                               Color::strikeout, Painter::line_solid, Painter::line_thin);
+                               Color::deletedtext, Painter::line_solid, Painter::line_thin);
                        running_strikeout = false;
                }
 
@@ -818,10 +852,13 @@ void RowPainter::paintText()
                        x_ += 2;
                        ++vpos;
                } else if (par_.isSeparator(pos)) {
+                       Font orig_font = text_.getFont(*bv_.buffer(), par_, pos);
+                       double const orig_x = x_;
                        x_ += width_pos;
                        if (pos >= body_pos)
                                x_ += separator_;
                        ++vpos;
+                       paintForeignMark(orig_x, orig_font);
                } else {
                        paintFromPos(vpos);
                }
@@ -830,18 +867,18 @@ void RowPainter::paintText()
        // if we reach the end of a struck out range, paint it
        if (running_strikeout) {
                // calculate 1/3 height of the buffer's default font
-               FontMetrics const & fm 
+               FontMetrics const & fm
                        = theFontMetrics(bv_.buffer()->params().getFont());
                int const middle = yo_ - fm.maxAscent() / 3;
                pain_.line(last_strikeout_x, middle, int(x_), middle,
-                       Color::strikeout, Painter::line_solid, Painter::line_thin);
+                       Color::deletedtext, Painter::line_solid, Painter::line_thin);
                running_strikeout = false;
        }
 }
 
 
 bool CursorOnRow(PainterInfo & pi, pit_type const pit,
-       RowList::const_iterator rit, LyXText const & text)
+       RowList::const_iterator rit, Text const & text)
 {
        // Is there a cursor on this row (or inside inset on row)
        Cursor & cur = pi.base.bv->cursor();
@@ -858,7 +895,7 @@ bool CursorOnRow(PainterInfo & pi, pit_type const pit,
 
 
 bool innerCursorOnRow(PainterInfo & pi, pit_type pit,
-       RowList::const_iterator rit, LyXText const & text)
+       RowList::const_iterator rit, Text const & text)
 {
        // Is there a cursor inside an inset on this row, and is this inset
        // the only "character" on this row
@@ -881,13 +918,21 @@ bool inNarrowInset(PainterInfo & pi)
 {
        // check whether the current inset is nested in a non-wide inset
        Cursor & cur = pi.base.bv->cursor();
-       for (int i = cur.depth() - 1; --i >= 0; ) {
+       Inset const * cur_in = &cur.inset();
+       // check all higher nested insets
+       for (size_type i = 1; i < cur.depth(); ++i) {
                Inset * const in = &cur[i].inset();
-               if (in) {
-                       InsetText * t = 
+               if (in == cur_in)
+                       // we reached the level of the current inset, so stop
+                       return false;
+               else if (in) {
+                       if (in->hasFixedWidth())
+                               return true;
+                       InsetText * t =
                                const_cast<InsetText *>(in->asTextInset());
-                       if (t)
-                               return !t->wide();
+                       if (t && !t->wide())
+                               // OK, we are in a non-wide() inset
+                               return true;
                }
        }
        return false;
@@ -895,7 +940,7 @@ bool inNarrowInset(PainterInfo & pi)
 
 
 void paintPar
-       (PainterInfo & pi, LyXText const & text, pit_type pit, int x, int y,
+       (PainterInfo & pi, Text const & text, pit_type pit, int x, int y,
         bool repaintAll)
 {
 //     lyxerr << "  paintPar: pit: " << pit << " at y: " << y << endl;
@@ -911,6 +956,8 @@ void paintPar
        RowList::const_iterator const rb = pm.rows().begin();
        RowList::const_iterator const re = pm.rows().end();
 
+       Bidi bidi;
+
        y -= rb->ascent();
        size_type rowno = 0;
        for (RowList::const_iterator rit = rb; rit != re; ++rit, ++rowno) {
@@ -925,7 +972,7 @@ void paintPar
                bool cursor_on_row = CursorOnRow(pi, pit, rit, text);
                bool in_inset_alone_on_row =
                        innerCursorOnRow(pi, pit, rit, text);
-               bool leftEdgeFixed = 
+               bool leftEdgeFixed =
                        (par.getAlign() == LYX_ALIGN_LEFT ||
                         par.getAlign() == LYX_ALIGN_BLOCK);
                bool inNarrowIns = inNarrowInset(pi);
@@ -957,11 +1004,11 @@ void paintPar
                                && y - rit->ascent() < ww);
                        // it is not needed to draw on screen if we are not inside.
                        pi.pain.setDrawingEnabled(inside);
-                       RowPainter rp(pi, text, pit, *rit, x, y);
+                       RowPainter rp(pi, text, pit, *rit, bidi, x, y);
                        // Clear background of this row
                        // (if paragraph background was not cleared)
                        if (!repaintAll &&
-                           (!(in_inset_alone_on_row && leftEdgeFixed
+                           (!(in_inset_alone_on_row && leftEdgeFixed && !inNarrowIns)
                                || row_has_changed)) {
                                pi.pain.fillRectangle(x, y - rit->ascent(),
                                    rp.maxWidth(), rit->height(),
@@ -987,7 +1034,7 @@ void paintPar
                        rp.paintChangeBar();
                        if (rit == rb)
                                rp.paintFirst();
-                       rp.paintText();
+                       rp.paintText();
                        if (rit + 1 == re)
                                rp.paintLast();
                }
@@ -1009,10 +1056,10 @@ void paintText(BufferView & bv,
 {
        BOOST_ASSERT(bv.buffer());
        Buffer const & buffer = *bv.buffer();
-       LyXText & text = buffer.text();
+       Text & text = buffer.text();
        bool const select = bv.cursor().selection();
        ViewMetricsInfo const & vi = bv.viewMetricsInfo();
-       
+
        PainterInfo pi(const_cast<BufferView *>(&bv), pain);
        // Should the whole screen, including insets, be refreshed?
        // FIXME: We should also distinguish DecorationUpdate to avoid text
@@ -1041,17 +1088,17 @@ void paintText(BufferView & bv,
 
        // and grey out above (should not happen later)
 //     lyxerr << "par ascent: " << text.getPar(vi.p1).ascent() << endl;
-       if (vi.y1 > 0 && vi.update_strategy != SingleParUpdate)
+       if (vi.y1 > 0 && vi.update_strategy == FullScreenUpdate)
                pain.fillRectangle(0, 0, bv.workWidth(), vi.y1, Color::bottomarea);
 
        // and possibly grey out below
 //     lyxerr << "par descent: " << text.getPar(vi.p1).ascent() << endl;
-       if (vi.y2 < bv.workHeight() && vi.update_strategy != SingleParUpdate)
+       if (vi.y2 < bv.workHeight() && vi.update_strategy == FullScreenUpdate)
                pain.fillRectangle(0, vi.y2, bv.workWidth(), bv.workHeight() - vi.y2, Color::bottomarea);
 }
 
 
-void paintTextInset(LyXText const & text, PainterInfo & pi, int x, int y)
+void paintTextInset(Text const & text, PainterInfo & pi, int x, int y)
 {
 //     lyxerr << "  paintTextInset: y: " << y << endl;
 
@@ -1059,7 +1106,7 @@ void paintTextInset(LyXText const & text, PainterInfo & pi, int x, int y)
        // This flag cannot be set from within same inset:
        bool repaintAll = refreshInside;
        for (int pit = 0; pit < int(text.paragraphs().size()); ++pit) {
-               ParagraphMetrics const & pmi 
+               ParagraphMetrics const & pmi
                        = pi.base.bv->parMetrics(&text, pit);
                y += pmi.ascent();
                paintPar(pi, text, pit, x, y, repaintAll);