]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiPainter.cpp
Amend f441590c
[lyx.git] / src / frontends / qt4 / GuiPainter.cpp
index b0a78c9db5f83efb6c21a9684a079b5d0d91b3ba..2b024d86a7996de136d90a0a37775ed222ab6a5d 100644 (file)
@@ -289,8 +289,44 @@ int GuiPainter::text(int x, int y, char_type c, FontInfo const & f)
 }
 
 
+void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const & f, QFont ff)
+{
+       setQPainterPen(computeColor(f.realColor()));
+       if (font() != ff)
+               setFont(ff);
+
+        /* In LyX, the character direction is forced by the language.
+         * Therefore, we have to signal that fact to Qt.
+         */
+#if 1
+       /* Use unicode override characters to enforce drawing direction
+        * Source: http://www.iamcal.com/understanding-bidirectional-text/
+        */
+       if (rtl)
+               // Right-to-left override: forces to draw text right-to-left
+               str = QChar(0x202E) + str;
+       else
+               // Left-to-right override: forces to draw text left-to-right
+               str =  QChar(0x202D) + str;
+       drawText(x, y, str);
+#else
+       /* This looks like a cleaner solution, but it has drawbacks
+        * - does not work reliably (Mac OS X, ...)
+        * - it is not really documented
+        * Keep it here for now, in case it can be helpful
+        */
+       //This is much stronger than setLayoutDirection.
+       int flag = rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+       drawText(x + (rtl ? textwidth : 0), y - fm.maxAscent(), 0, 0,
+                flag | Qt::TextDontClip,
+                str);
+#endif
+}
+
+
 int GuiPainter::text(int x, int y, docstring const & s,
-                    FontInfo const & f, bool const rtl)
+                     FontInfo const & f, bool const rtl,
+                     double const wordspacing)
 {
        //LYXERR0("text: x=" << x << ", s=" << s);
        if (s.empty())
@@ -316,13 +352,15 @@ int GuiPainter::text(int x, int y, docstring const & s,
                str = ' ' + str;
 #endif
 
-       QFont const & ff = getFont(f);
+       QFont ff = getFont(f);
+       ff.setWordSpacing(wordspacing);
        GuiFontMetrics const & fm = getFontMetrics(f);
 
        // Here we use the font width cache instead of
        //   textwidth = fontMetrics().width(str);
        // because the above is awfully expensive on MacOSX
-       int const textwidth = fm.width(s);
+       // Note that we have to take in account space stretching (word spacing)
+       int const textwidth = fm.width(s) + count(s.begin(), s.end(), ' ') * wordspacing;
 
        if (!isDrawingEnabled())
                return textwidth;
@@ -339,6 +377,8 @@ int GuiPainter::text(int x, int y, docstring const & s,
                // Only the left bearing of the first character is important
                // as we always write from left to right, even for
                // right-to-left languages.
+               // FIXME: this is probably broken for RTL now that we draw full strings.
+               // Morover the first/last element is possibly not the right one since the glyph may have changed.
                int const lb = min(fm.lbearing(s[0]), 0);
                int const mA = fm.maxAscent();
                if (QPixmapCache::find(key, pm)) {
@@ -362,12 +402,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
 #endif
                        pm.fill(Qt::transparent);
                        GuiPainter p(&pm, pixelRatio());
-                       p.setQPainterPen(computeColor(f.realColor()));
-                       if (p.font() != ff)
-                               p.setFont(ff);
-                       // We need to draw the text as LTR as we use our own bidi code.
-                       p.setLayoutDirection(Qt::LeftToRight);
-                       p.drawText(-lb, mA, str);
+                       p.do_drawText(-lb, mA, str, rtl, f, ff);
                        QPixmapCache::insert(key, pm);
                        //LYXERR(Debug::PAINTING, "h=" << h << "  mA=" << mA << "  mD=" << mD
                        //      << "  w=" << w << "  lb=" << lb << "  tw=" << textwidth
@@ -375,57 +410,29 @@ int GuiPainter::text(int x, int y, docstring const & s,
 
                        // Draw the new cached pixmap.
                        drawPixmap(x + lb, y - mA, pm);
-
-                       return textwidth;
+                       //rectangle(x-lb, y-mA, w, h, Color_green);
                }
+               return textwidth;
        }
 
        // don't use the pixmap cache,
-       // draw directly onto the painting device
-       setQPainterPen(computeColor(f.realColor()));
-       if (font() != ff)
-               setFont(ff);
-
-        /* In LyX, the character direction is forced by the language.
-         * Therefore, we have to signal that fact to Qt.
-         */
-#if 1
-       /* Use unicode override characters to enforce drawing direction
-        * Source: http://www.iamcal.com/understanding-bidirectional-text/
-        */
-       if (rtl)
-               // Right-to-left override: forces to draw text right-to-left
-               str = QChar(0x202E) + str;
-       else
-               // Left-to-right override: forces to draw text left-to-right
-               str =  QChar(0x202D) + str;
-       drawText(x, y, str);
-#else
-       /* This looks like a cleaner solution, but it has drawbacks
-        * - does not work reliably (Mac OS X, ...)
-        * - it is not really documented
-        * Keep it here for now, in case it can be helpful
-        */
-       //This is much stronger than setLayoutDirection.
-       int flag = rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
-       drawText(x + (rtl ? textwidth : 0), y - fm.maxAscent(), 0, 0,
-                flag | Qt::TextDontClip,
-                str);
-#endif
+       do_drawText(x, y, str, rtl, f, ff);
        //LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
        //      << " at " << x << "," << y);
        return textwidth;
 }
 
 
-int GuiPainter::text(int x, int y, docstring const & str, Font const & f)
+int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
+                     double const wordspacing)
 {
-       return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft());
+       return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft(), wordspacing);
 }
 
 
 int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
-                    Color other, size_type from, size_type to)
+                     Color other, size_type const from, size_type const to,
+                     double const wordspacing)
 {
        GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
        FontInfo fi = f.fontInfo();
@@ -434,8 +441,8 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
        // dimensions
        int const ascent = fm.maxAscent();
        int const height = fm.maxAscent() + fm.maxDescent();
-       int xmin = fm.pos2x(str, from, rtl);
-       int xmax = fm.pos2x(str, to, rtl);
+       int xmin = fm.pos2x(str, from, rtl, wordspacing);
+       int xmax = fm.pos2x(str, to, rtl, wordspacing);
        if (xmin > xmax)
                swap(xmin, xmax);
 
@@ -444,7 +451,7 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
        fi.setPaintColor(other);
        QRegion const clip(x + xmin, y - ascent, xmax - xmin, height);
        setClipRegion(clip);
-       int const textwidth = text(x, y, str, fi, rtl);
+       int const textwidth = text(x, y, str, fi, rtl, wordspacing);
 
        // Then the part in normal color
        // Note that in Qt5, it is not possible to use Qt::UniteClip,
@@ -452,7 +459,7 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
        fi.setPaintColor(orig);
        QRegion region(viewport());
        setClipRegion(region - clip);
-       text(x, y, str, fi, rtl);
+       text(x, y, str, fi, rtl, wordspacing);
        setClipping(false);
 
        return textwidth;
@@ -566,42 +573,37 @@ int GuiPainter::preeditText(int x, int y, char_type c,
 }
 
 
-void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
+void GuiPainter::underline(FontInfo const & f, int x, int y, int width,
+                           line_style ls)
 {
        FontMetrics const & fm = theFontMetrics(f);
+       int const pos = fm.underlinePos();
 
-       int const below = max(fm.maxDescent() / 2, 2);
-
-       line(x, y + below, x + width, y + below, f.realColor());
-       line(x, y + below - 2, x + width, y + below - 2, f.realColor());
+       line(x, y + pos, x + width, y + pos,
+            f.realColor(), ls, fm.lineWidth());
 }
 
 
-void GuiPainter::underline(FontInfo const & f, int x, int y, int width)
+void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
 {
        FontMetrics const & fm = theFontMetrics(f);
+       int const pos = fm.strikeoutPos();
 
-       int const below = max(fm.maxDescent() / 2, 2);
-       int const height = max((fm.maxDescent() / 4) - 1, 1);
-
-       if (height < 2)
-               line(x, y + below, x + width, y + below, f.realColor());
-       else
-               fillRectangle(x, y + below, width, below + height, f.realColor());
+       line(x, y - pos, x + width, y - pos,
+            f.realColor(), line_solid, fm.lineWidth());
 }
 
 
-void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
+void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
 {
        FontMetrics const & fm = theFontMetrics(f);
+       int const pos1 = fm.underlinePos() + fm.lineWidth();
+       int const pos2 = fm.underlinePos() - fm.lineWidth() + 1;
 
-       int const middle = max((fm.maxHeight() / 4), 1);
-       int const height =  middle/3;
-
-       if (height < 2)
-               line(x, y - middle, x + width, y - middle, f.realColor());
-       else
-               fillRectangle(x, y - middle, width, height, f.realColor());
+       line(x, y + pos1, x + width, y + pos1,
+                f.realColor(), line_solid, fm.lineWidth());
+       line(x, y + pos2, x + width, y + pos2,
+                f.realColor(), line_solid, fm.lineWidth());
 }