]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiPainter.cpp
Use QFontMetrics information for underlines (and friends) width and position
[lyx.git] / src / frontends / qt4 / GuiPainter.cpp
index 95ab52a98f34b76fb4730e71c52f56fa44ca731a..2ecd3acd66d1020455496d8391404fdfa6a2ed56 100644 (file)
@@ -9,10 +9,6 @@
  * Full author contact details are available in file CREDITS.
  */
 
-#ifdef Q_OS_MAC
-#define USE_RTL_OVERRIDE 1
-#endif
-
 #include <config.h>
 
 #include "GuiPainter.h"
@@ -38,7 +34,7 @@
 
 // Set USE_PIXMAP_CACHE to 1 for enabling the use of a Pixmap cache when
 // drawing text. This is especially useful for older PPC/Mac systems.
-#if defined(Q_WS_X11)
+#if defined(Q_WS_X11) || defined(QPA_XCB)
 #define USE_PIXMAP_CACHE 0
 #else
 #define USE_PIXMAP_CACHE 1
@@ -49,8 +45,8 @@ using namespace lyx::support;
 
 namespace lyx {
 namespace frontend {
-  
-const float Painter::thin_line = 0.0;
+
+const int Painter::thin_line = 0;
 
 GuiPainter::GuiPainter(QPaintDevice * device, double pixel_ratio)
        : QPainter(device), Painter(pixel_ratio),
@@ -71,7 +67,7 @@ GuiPainter::~GuiPainter()
 
 
 void GuiPainter::setQPainterPen(QColor const & col,
-       Painter::line_style ls, float lw)
+       Painter::line_style ls, int lw)
 {
        if (col == current_color_ && ls == current_ls_ && lw == current_lw_)
                return;
@@ -88,7 +84,7 @@ void GuiPainter::setQPainterPen(QColor const & col,
                case line_onoffdash: pen.setStyle(Qt::DotLine); break;
        }
 
-       pen.setWidthF(lw);
+       pen.setWidth(lw);
 
        setPen(pen);
 }
@@ -180,7 +176,7 @@ void GuiPainter::point(int x, int y, Color col)
 void GuiPainter::line(int x1, int y1, int x2, int y2,
        Color col,
        line_style ls,
-       float lw)
+       int lw)
 {
        if (!isDrawingEnabled())
                return;
@@ -198,7 +194,7 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
        Color col,
        fill_style fs,
        line_style ls,
-       float lw)
+       int lw)
 {
        if (!isDrawingEnabled())
                return;
@@ -236,7 +232,7 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
 void GuiPainter::rectangle(int x, int y, int w, int h,
        Color col,
        line_style ls,
-       float lw)
+       int lw)
 {
        if (!isDrawingEnabled())
                return;
@@ -294,7 +290,8 @@ int GuiPainter::text(int x, int y, char_type c, FontInfo const & f)
 
 
 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())
@@ -320,7 +317,8 @@ 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
@@ -333,27 +331,6 @@ int GuiPainter::text(int x, int y, docstring const & s,
 
        textDecoration(f, x, y, textwidth);
 
-       // Qt4 does not display a glyph whose codepoint is the
-       // same as that of a soft-hyphen (0x00ad), unless it
-       // occurs at a line-break. As a kludge, we force Qt to
-       // render this glyph using a one-column line.
-       // This is needed for some math glyphs.
-       // Should the soft hyphen char be displayed at all?
-       // I don't think so (i.e., Qt is correct as far as
-       // texted is concerned). /spitz
-       if (s.size() == 1 && str[0].unicode() == 0x00ad) {
-               setQPainterPen(computeColor(f.realColor()));
-               QTextLayout adsymbol(str);
-               adsymbol.setFont(ff);
-               adsymbol.beginLayout();
-               QTextLine line = adsymbol.createLine();
-               line.setNumColumns(1);
-               line.setPosition(QPointF(0, -line.ascent()));
-               adsymbol.endLayout();
-               line.draw(this, QPointF(x, y));
-               return textwidth;
-       }
-
        if (use_pixmap_cache_) {
                QPixmap pm;
                QString key = generateStringSignature(str, f);
@@ -380,7 +357,8 @@ int GuiPainter::text(int x, int y, docstring const & s,
                int const mD = fm.maxDescent();
                int const h = mA + mD;
                if (w > 0 && h > 0) {
-                       pm = QPixmap(pixelRatio() * w , pixelRatio() * h);
+                       pm = QPixmap(static_cast<int>(pixelRatio() * w),
+                                                static_cast<int>(pixelRatio() * h));
 #if QT_VERSION >= 0x050000
                        pm.setDevicePixelRatio(pixelRatio());
 #endif
@@ -413,7 +391,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
         /* In LyX, the character direction is forced by the language.
          * Therefore, we have to signal that fact to Qt.
          */
-#ifdef USE_RTL_OVERRIDE
+#if 1
        /* Use unicode override characters to enforce drawing direction
         * Source: http://www.iamcal.com/understanding-bidirectional-text/
         */
@@ -425,9 +403,10 @@ int GuiPainter::text(int x, int y, docstring const & s,
                str =  QChar(0x202D) + str;
        drawText(x, y, str);
 #else
-       /* This is a cleanr solution, but it has two drawbacks
-        * - it seems that it does not work under Mac OS X
+       /* 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;
@@ -441,14 +420,16 @@ int GuiPainter::text(int x, int y, docstring const & s,
 }
 
 
-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();
@@ -457,8 +438,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);
 
@@ -467,7 +448,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,
@@ -475,7 +456,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;
@@ -589,42 +570,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());
 }