]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiPainter.cpp
QDialogButtonBox for the remaining dialogs.
[lyx.git] / src / frontends / qt4 / GuiPainter.cpp
index a622940b9d4253a7032ec1522ac17244b87f4860..2c6529a9381046fde8a9dfb9ea81cd7083f1c0ce 100644 (file)
 #include "qt_helpers.h"
 
 #include "Font.h"
-#include "Language.h"
 #include "LyXRC.h"
 
-#include "insets/Inset.h"
-
-#include "support/lassert.h"
 #include "support/debug.h"
+#include "support/lassert.h"
+#include "support/lyxlib.h"
+
+#include <algorithm>
 
 #include <QPixmapCache>
 #include <QTextLayout>
@@ -52,10 +52,10 @@ GuiPainter::GuiPainter(QPaintDevice * device, double pixel_ratio)
        : QPainter(device), Painter(pixel_ratio),
          use_pixmap_cache_(lyxrc.use_pixmap_cache && USE_PIXMAP_CACHE)
 {
-       // new QPainter has default QPen:
-       current_color_ = guiApp->colorCache().get(Color_black);
-       current_ls_ = line_solid;
-       current_lw_ = thin_line;
+       // set cache correctly
+       current_color_ = pen().color();
+       current_ls_ = pen().style() == Qt::DotLine ? line_onoffdash : line_solid;
+       current_lw_ = pen().width();
 }
 
 
@@ -80,8 +80,11 @@ void GuiPainter::setQPainterPen(QColor const & col,
        pen.setColor(col);
 
        switch (ls) {
-               case line_solid: pen.setStyle(Qt::SolidLine); break;
-               case line_onoffdash: pen.setStyle(Qt::DotLine); break;
+       case line_solid:
+       case line_solid_aliased:
+               pen.setStyle(Qt::SolidLine); break;
+       case line_onoffdash:
+               pen.setStyle(Qt::DotLine); break;
        }
 
        pen.setWidth(lw);
@@ -131,15 +134,15 @@ QColor GuiPainter::filterColor(QColor const & col)
        // map into [min,max] interval
        QColor const & min = monochrome_min_.top();
        QColor const & max = monochrome_max_.top();
-                       
+
        qreal v = col.valueF();
        v *= v; // make it a bit steeper (i.e. darker)
-               
+
        qreal minr, ming, minb;
        qreal maxr, maxg, maxb;
        min.getRgbF(&minr, &ming, &minb);
        max.getRgbF(&maxr, &maxg, &maxb);
-                       
+
        QColor c;
        c.setRgbF(
                v * (minr - maxr) + maxr,
@@ -168,9 +171,6 @@ void GuiPainter::leaveMonochromeMode()
 
 void GuiPainter::point(int x, int y, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col));
        drawPoint(x, y);
 }
@@ -181,12 +181,9 @@ void GuiPainter::line(int x1, int y1, int x2, int y2,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col), ls, lw);
        bool const do_antialiasing = renderHints() & TextAntialiasing
-               && x1 != x2 && y1 != y2;
+               && x1 != x2 && y1 != y2 && ls != line_solid_aliased;
        setRenderHint(Antialiasing, do_antialiasing);
        drawLine(x1, y1, x2, y2);
        setRenderHint(Antialiasing, false);
@@ -199,15 +196,14 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        // double the size if needed
        // FIXME THREAD
        static QVector<QPoint> points(32);
        if (np > points.size())
                points.resize(2 * np);
 
+       // Note: the proper way to not get blurry vertical and horizontal lines is
+       // to add 0.5 to all coordinates.
        bool antialias = false;
        for (int i = 0; i < np; ++i) {
                points[i].setX(xp[i]);
@@ -218,7 +214,8 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
        QColor const color = computeColor(col);
        setQPainterPen(color, ls, lw);
        bool const text_is_antialiased = renderHints() & TextAntialiasing;
-       setRenderHint(Antialiasing, antialias && text_is_antialiased);
+       setRenderHint(Antialiasing,
+                     antialias && text_is_antialiased && ls != line_solid_aliased);
        if (fs == fill_none) {
                drawPolyline(points.data(), np);
        } else {
@@ -241,9 +238,6 @@ void GuiPainter::path(int const * xp, int const * yp,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        QPainterPath bpath;
        // This is the starting point, so its control points are meaningless
        bpath.moveTo(xp[0], yp[0]);
@@ -259,7 +253,7 @@ void GuiPainter::path(int const * xp, int const * yp,
        QColor const color = computeColor(col);
        setQPainterPen(color, ls, lw);
        bool const text_is_antialiased = renderHints() & TextAntialiasing;
-       setRenderHint(Antialiasing, text_is_antialiased);
+       setRenderHint(Antialiasing, text_is_antialiased && ls != line_solid_aliased);
        drawPath(bpath);
        if (fs != fill_none)
                fillPath(bpath, QBrush(color));
@@ -272,9 +266,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col), ls, lw);
        drawRect(x, y, w, h);
 }
@@ -282,9 +273,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
 
 void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        fillRect(x, y, w, h, guiApp->colorCache().get(col));
 }
 
@@ -292,9 +280,6 @@ void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col)
 void GuiPainter::arc(int x, int y, unsigned int w, unsigned int h,
        int a1, int a2, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        // LyX usings 1/64ths degree, Qt usings 1/16th
        setQPainterPen(computeColor(col));
        bool const do_antialiasing = renderHints() & TextAntialiasing;
@@ -311,9 +296,6 @@ void GuiPainter::image(int x, int y, int w, int h, graphics::Image const & i)
 
        fillRectangle(x, y, w, h, Color_graphicsbg);
 
-       if (!isDrawingEnabled())
-               return;
-
        QImage const image = qlimage.image();
        QRectF const drect = QRectF(x, y, w, h);
        QRectF const srect = QRectF(0, 0, image.width(), image.height());
@@ -335,11 +317,13 @@ void GuiPainter::text(int x, int y, char_type c, FontInfo const & f)
 
 void GuiPainter::text(int x, int y, docstring const & s, FontInfo const & f)
 {
-       text(x, y, s, f, false, 0.0, 0.0);
+       text(x, y, s, f, Auto, 0.0, 0.0);
 }
 
 
-void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const & f, QFont ff)
+void GuiPainter::do_drawText(int x, int y, QString str,
+                             GuiPainter::Direction const dir,
+                             FontInfo const & f, QFont ff)
 {
        setQPainterPen(computeColor(f.realColor()));
        if (font() != ff)
@@ -352,10 +336,10 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
        /* Use unicode override characters to enforce drawing direction
         * Source: http://www.iamcal.com/understanding-bidirectional-text/
         */
-       if (rtl)
+       if (dir == RtL)
                // Right-to-left override: forces to draw text right-to-left
                str = QChar(0x202E) + str;
-       else
+       else if (dir == LtR)
                // Left-to-right override: forces to draw text left-to-right
                str =  QChar(0x202D) + str;
        drawText(x, y, str);
@@ -366,8 +350,12 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
         * 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,
+       int flag = 0;
+       if (dir == RtL)
+               flag = Qt::TextForceRightToLeft;
+       else if (dir == LtR)
+               flag = Qt::TextForceLeftToRight;
+       drawText(x + ((dir == RtL) ? textwidth : 0), y - fm.maxAscent(), 0, 0,
                 flag | Qt::TextDontClip,
                 str);
 #endif
@@ -375,11 +363,11 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
 
 
 void GuiPainter::text(int x, int y, docstring const & s,
-                      FontInfo const & f, bool const rtl,
+                      FontInfo const & f, Direction const dir,
                       double const wordspacing, double const tw)
 {
        //LYXERR0("text: x=" << x << ", s=" << s);
-       if (s.empty() || !isDrawingEnabled())
+       if (s.empty())
                return;
 
        /* Caution: The following ucs4 to QString conversions work for symbol fonts
@@ -409,7 +397,8 @@ void GuiPainter::text(int x, int y, docstring const & s,
        int textwidth = 0;
        if (tw == 0.0)
                // Note that we have to take in account space stretching (word spacing)
-               textwidth = fm.width(s) + count(s.begin(), s.end(), ' ') * wordspacing;
+               textwidth = fm.width(s) +
+                       static_cast<int>(fm.countExpanders(s) * wordspacing);
        else
                textwidth = static_cast<int>(tw);
 
@@ -450,7 +439,7 @@ void GuiPainter::text(int x, int y, docstring const & s,
 #endif
                        pm.fill(Qt::transparent);
                        GuiPainter p(&pm, pixelRatio());
-                       p.do_drawText(-lb, mA, str, rtl, f, ff);
+                       p.do_drawText(-lb, mA, str, dir, f, ff);
                        QPixmapCache::insert(key, pm);
                        //LYXERR(Debug::PAINTING, "h=" << h << "  mA=" << mA << "  mD=" << mD
                        //      << "  w=" << w << "  lb=" << lb << "  tw=" << textwidth
@@ -463,8 +452,18 @@ void GuiPainter::text(int x, int y, docstring const & s,
                return;
        }
 
-       // don't use the pixmap cache,
-       do_drawText(x, y, str, rtl, f, ff);
+       // don't use the pixmap cache
+       setQPainterPen(computeColor(f.realColor()));
+       if (dir != Auto) {
+               shared_ptr<QTextLayout const> ptl =
+                       fm.getTextLayout(s, dir == RtL, wordspacing);
+               ptl->draw(this, QPointF(x, y - fm.maxAscent()));
+       }
+       else {
+               if (font() != ff)
+                       setFont(ff);
+               drawText(x, y, str);
+       }
        //LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
        //      << " at " << x << "," << y);
 }
@@ -473,7 +472,8 @@ void GuiPainter::text(int x, int y, docstring const & s,
 void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
                       double const wordspacing, double const tw)
 {
-       text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft(), wordspacing, tw);
+       text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft() ? RtL : LtR,
+            wordspacing, tw);
 }
 
 
@@ -483,13 +483,13 @@ void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
 {
        GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
        FontInfo fi = f.fontInfo();
-       bool const rtl = f.isVisibleRightToLeft();
+       Direction const dir = f.isVisibleRightToLeft() ? RtL : LtR;
 
        // dimensions
        int const ascent = fm.maxAscent();
        int const height = fm.maxAscent() + fm.maxDescent();
-       int xmin = fm.pos2x(str, from, rtl, wordspacing);
-       int xmax = fm.pos2x(str, to, rtl, wordspacing);
+       int xmin = fm.pos2x(str, from, dir == RtL, wordspacing);
+       int xmax = fm.pos2x(str, to, dir == RtL, wordspacing);
        if (xmin > xmax)
                swap(xmin, xmax);
 
@@ -498,7 +498,7 @@ void 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);
-       text(x, y, str, fi, rtl, wordspacing, tw);
+       text(x, y, str, fi, dir, wordspacing, tw);
 
        // Then the part in normal color
        // Note that in Qt5, it is not possible to use Qt::UniteClip,
@@ -506,7 +506,7 @@ void 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, wordspacing, tw);
+       text(x, y, str, fi, dir, wordspacing, tw);
        setClipping(false);
 }
 
@@ -517,6 +517,8 @@ void GuiPainter::textDecoration(FontInfo const & f, int x, int y, int width)
                underline(f, x, y, width);
        if (f.strikeout() == FONT_ON)
                strikeoutLine(f, x, y, width);
+       if (f.xout() == FONT_ON)
+               crossoutLines(f, x, y, width);
        if (f.uuline() == FONT_ON)
                doubleUnderline(f, x, y, width);
        if (f.uwave() == FONT_ON)
@@ -528,31 +530,10 @@ void GuiPainter::textDecoration(FontInfo const & f, int x, int y, int width)
 static int max(int a, int b) { return a > b ? a : b; }
 
 
-void GuiPainter::button(int x, int y, int w, int h, bool mouseHover)
-{
-       if (mouseHover)
-               fillRectangle(x, y, w, h, Color_buttonhoverbg);
-       else
-               fillRectangle(x, y, w, h, Color_buttonbg);
-       buttonFrame(x, y, w, h);
-}
-
-
-void GuiPainter::buttonFrame(int x, int y, int w, int h)
-{
-       line(x, y, x, y + h - 1, Color_buttonframe);
-       line(x - 1 + w, y, x - 1 + w, y + h - 1, Color_buttonframe);
-       line(x, y - 1, x - 1 + w, y - 1, Color_buttonframe);
-       line(x, y + h - 1, x - 1 + w, y + h - 1, Color_buttonframe);
-}
-
-
 void GuiPainter::rectText(int x, int y, docstring const & str,
        FontInfo const & font, Color back, Color frame)
 {
-       int width;
-       int ascent;
-       int descent;
+       int width, ascent, descent;
 
        FontMetrics const & fm = theFontMetrics(font);
        fm.rectText(str, width, ascent, descent);
@@ -564,24 +545,25 @@ void GuiPainter::rectText(int x, int y, docstring const & str,
        if (frame != Color_none)
                rectangle(x, y - ascent, width, ascent + descent, frame);
 
+       // FIXME: let offset depend on font
        text(x + 3, y, str, font);
 }
 
 
-void GuiPainter::buttonText(int x, int y, docstring const & str,
-       FontInfo const & font, bool mouseHover)
+void GuiPainter::buttonText(int x, int baseline, docstring const & s,
+       FontInfo const & font, Color back, Color frame, int offset)
 {
-       int width;
-       int ascent;
-       int descent;
+       int width, ascent, descent;
 
        FontMetrics const & fm = theFontMetrics(font);
-       fm.buttonText(str, width, ascent, descent);
+       fm.buttonText(s, offset, width, ascent, descent);
 
-       static int const d = Inset::TEXT_TO_INSET_OFFSET / 2;
+       static int const d = offset / 2;
 
-       button(x + d, y - ascent, width - Inset::TEXT_TO_INSET_OFFSET, descent + ascent, mouseHover);
-       text(x + Inset::TEXT_TO_INSET_OFFSET, y, str, font);
+       fillRectangle(x + d + 1, baseline - ascent + 1, width - offset - 1,
+                             ascent + descent - 1, back);
+       rectangle(x + d, baseline - ascent, width - offset, ascent + descent, frame);
+       text(x + offset, baseline, s, font);
 }
 
 
@@ -639,6 +621,20 @@ void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
 }
 
 
+void GuiPainter::crossoutLines(FontInfo const & f, int x, int y, int width)
+{
+       FontInfo tmpf = f;
+       tmpf.setXout(FONT_OFF);
+
+       // the definition of \xout in ulem.sty is
+    //  \def\xout{\bgroup \markoverwith{\hbox to.35em{\hss/\hss}}\ULon}
+       // Let's mimick it somewhat.
+       double offset = max(0.35 * theFontMetrics(tmpf).em(), 1);
+       for (int i = 0 ; i < iround(width / offset) ; ++i)
+               text(x + iround(i * offset), y, '/', tmpf);
+}
+
+
 void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
 {
        FontMetrics const & fm = theFontMetrics(f);