Skip to content
Snippets Groups Projects
qwt_text_engine.cpp 8.59 KiB
Newer Older
  • Learn to ignore specific revisions
  • pixhawk's avatar
    pixhawk committed
    /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
     * Qwt Widget Library
     * Copyright (C) 1997   Josef Wilgen
     * Copyright (C) 2003   Uwe Rathmann
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the Qwt License, Version 1.0
     *****************************************************************************/
    
    
    Bryant's avatar
    Bryant committed
    #include "qwt_text_engine.h"
    #include "qwt_math.h"
    #include "qwt_painter.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <qpainter.h>
    #include <qpixmap.h>
    #include <qimage.h>
    #include <qmap.h>
    #include <qwidget.h>
    
    Bryant's avatar
    Bryant committed
    #include <qtextobject.h>
    #include <qtextdocument.h>
    #include <qabstracttextdocumentlayout.h>
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    static QString taggedRichText( const QString &text, int flags )
    
    pixhawk's avatar
    pixhawk committed
    {
        QString richText = text;
    
        // By default QSimpleRichText is Qt::AlignLeft
    
    Bryant's avatar
    Bryant committed
        if ( flags & Qt::AlignJustify )
        {
            richText.prepend( QString::fromLatin1( "<div align=\"justify\">" ) );
            richText.append( QString::fromLatin1( "</div>" ) );
        }
        else if ( flags & Qt::AlignRight )
        {
            richText.prepend( QString::fromLatin1( "<div align=\"right\">" ) );
            richText.append( QString::fromLatin1( "</div>" ) );
        }
        else if ( flags & Qt::AlignHCenter )
        {
            richText.prepend( QString::fromLatin1( "<div align=\"center\">" ) );
            richText.append( QString::fromLatin1( "</div>" ) );
    
    pixhawk's avatar
    pixhawk committed
        }
    
        return richText;
    }
    
    class QwtRichTextDocument: public QTextDocument
    {
    public:
    
    Bryant's avatar
    Bryant committed
        QwtRichTextDocument( const QString &text, int flags, const QFont &font )
        {
            setUndoRedoEnabled( false );
            setDefaultFont( font );
            setHtml( text );
    
    pixhawk's avatar
    pixhawk committed
    
            // make sure we have a document layout
    
    Bryant's avatar
    Bryant committed
            ( void )documentLayout();
    
    pixhawk's avatar
    pixhawk committed
    
            QTextOption option = defaultTextOption();
            if ( flags & Qt::TextWordWrap )
    
    Bryant's avatar
    Bryant committed
                option.setWrapMode( QTextOption::WordWrap );
    
    pixhawk's avatar
    pixhawk committed
            else
    
    Bryant's avatar
    Bryant committed
                option.setWrapMode( QTextOption::NoWrap );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            option.setAlignment( static_cast<Qt::Alignment>( flags ) );
            setDefaultTextOption( option );
    
    pixhawk's avatar
    pixhawk committed
    
            QTextFrame *root = rootFrame();
            QTextFrameFormat fm = root->frameFormat();
    
    Bryant's avatar
    Bryant committed
            fm.setBorder( 0 );
            fm.setMargin( 0 );
            fm.setPadding( 0 );
            fm.setBottomMargin( 0 );
            fm.setLeftMargin( 0 );
            root->setFrameFormat( fm );
    
    pixhawk's avatar
    pixhawk committed
    
            adjustSize();
        }
    };
    
    class QwtPlainTextEngine::PrivateData
    {
    public:
    
    Bryant's avatar
    Bryant committed
        int effectiveAscent( const QFont &font ) const
        {
    
    pixhawk's avatar
    pixhawk committed
            const QString fontKey = font.key();
    
    
            QMap<QString, int>::const_iterator it =
    
    Bryant's avatar
    Bryant committed
                d_ascentCache.find( fontKey );
            if ( it == d_ascentCache.end() )
            {
                int ascent = findAscent( font );
                it = d_ascentCache.insert( fontKey, ascent );
    
    pixhawk's avatar
    pixhawk committed
            }
    
    
    Bryant's avatar
    Bryant committed
            return ( *it );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    private:
    
    Bryant's avatar
    Bryant committed
        int findAscent( const QFont &font ) const
        {
            static const QString dummy( "E" );
            static const QColor white( Qt::white );
    
            const QFontMetrics fm( font );
            QPixmap pm( fm.width( dummy ), fm.height() );
            pm.fill( white );
    
            QPainter p( &pm );
            p.setFont( font );
            p.drawText( 0, 0,  pm.width(), pm.height(), 0, dummy );
    
    pixhawk's avatar
    pixhawk committed
            p.end();
    
            const QImage img = pm.toImage();
    
            int row = 0;
    
    Bryant's avatar
    Bryant committed
            for ( row = 0; row < img.height(); row++ )
            {
                const QRgb *line = reinterpret_cast<const QRgb *>( 
                    img.scanLine( row ) );
    
    pixhawk's avatar
    pixhawk committed
    
                const int w = pm.width();
    
    Bryant's avatar
    Bryant committed
                for ( int col = 0; col < w; col++ )
                {
    
    pixhawk's avatar
    pixhawk committed
                    if ( line[col] != white.rgb() )
                        return fm.ascent() - row + 1;
                }
            }
    
            return fm.ascent();
    
    pixhawk's avatar
    pixhawk committed
    
        mutable QMap<QString, int> d_ascentCache;
    };
    
    //! Constructor
    QwtTextEngine::QwtTextEngine()
    {
    }
    
    //! Destructor
    QwtTextEngine::~QwtTextEngine()
    {
    }
    
    //! Constructor
    QwtPlainTextEngine::QwtPlainTextEngine()
    {
        d_data = new PrivateData;
    }
    
    //! Destructor
    QwtPlainTextEngine::~QwtPlainTextEngine()
    {
        delete d_data;
    }
    
    /*!
       Find the height for a given width
    
       \param font Font of the text
       \param flags Bitwise OR of the flags used like in QPainter::drawText
       \param text Text to be rendered
    
       \param width Width
    
    pixhawk's avatar
    pixhawk committed
    
       \return Calculated height
    */
    
    Bryant's avatar
    Bryant committed
    double QwtPlainTextEngine::heightForWidth( const QFont& font, int flags,
            const QString& text, double width ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const QFontMetricsF fm( font );
        const QRectF rect = fm.boundingRect(
            QRectF( 0, 0, width, QWIDGETSIZE_MAX ), flags, text );
    
    pixhawk's avatar
    pixhawk committed
    
        return rect.height();
    }
    
    /*!
      Returns the size, that is needed to render text
    
      \param font Font of the text
      \param flags Bitwise OR of the flags used like in QPainter::drawText
      \param text Text to be rendered
    
      \return Caluclated size
    */
    
    Bryant's avatar
    Bryant committed
    QSizeF QwtPlainTextEngine::textSize( const QFont &font,
        int flags, const QString& text ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const QFontMetricsF fm( font );
        const QRectF rect = fm.boundingRect(
            QRectF( 0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ), flags, text );
    
    pixhawk's avatar
    pixhawk committed
    
        return rect.size();
    }
    
    /*!
      Return margins around the texts
    
      \param font Font of the text
      \param left Return 0
      \param right Return 0
      \param top Return value for the top margin
      \param bottom Return value for the bottom margin
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPlainTextEngine::textMargins( const QFont &font, const QString &,
        double &left, double &right, double &top, double &bottom ) const
    
    pixhawk's avatar
    pixhawk committed
    {
        left = right = top = 0;
    
    
    Bryant's avatar
    Bryant committed
        const QFontMetricsF fm( font );
        top = fm.ascent() - d_data->effectiveAscent( font );
        bottom = fm.descent();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \brief Draw the text in a clipping rectangle
    
    pixhawk's avatar
    pixhawk committed
      A wrapper for QPainter::drawText.
    
      \param painter Painter
      \param rect Clipping rectangle
      \param flags Bitwise OR of the flags used like in QPainter::drawText
      \param text Text to be rendered
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPlainTextEngine::draw( QPainter *painter, const QRectF &rect,
        int flags, const QString& text ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtPainter::drawText( painter, rect, flags, text );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
      Test if a string can be rendered by this text engine.
      \return Always true. All texts can be rendered by QwtPlainTextEngine
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtPlainTextEngine::mightRender( const QString & ) const
    
    pixhawk's avatar
    pixhawk committed
    {
        return true;
    }
    
    #ifndef QT_NO_RICHTEXT
    
    //! Constructor
    QwtRichTextEngine::QwtRichTextEngine()
    {
    }
    
    /*!
       Find the height for a given width
    
    pixhawk's avatar
    pixhawk committed
       \param font Font of the text
    
    Bryant's avatar
    Bryant committed
       \param flags Bitwise OR of the flags used like in QPainter::drawText()
    
    pixhawk's avatar
    pixhawk committed
       \param text Text to be rendered
    
       \param width Width
    
    pixhawk's avatar
    pixhawk committed
    
       \return Calculated height
    */
    
    Bryant's avatar
    Bryant committed
    double QwtRichTextEngine::heightForWidth( const QFont& font, int flags,
            const QString& text, double width ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtRichTextDocument doc( text, flags, font );
    
        doc.setPageSize( QSizeF( width, QWIDGETSIZE_MAX ) );
        return doc.documentLayout()->documentSize().height();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Returns the size, that is needed to render text
    
    pixhawk's avatar
    pixhawk committed
      \param font Font of the text
    
    Bryant's avatar
    Bryant committed
      \param flags Bitwise OR of the flags used like in QPainter::drawText()
    
    pixhawk's avatar
    pixhawk committed
      \param text Text to be rendered
    
      \return Caluclated size
    */
    
    
    Bryant's avatar
    Bryant committed
    QSizeF QwtRichTextEngine::textSize( const QFont &font,
        int flags, const QString& text ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtRichTextDocument doc( text, flags, font );
    
    pixhawk's avatar
    pixhawk committed
    
        QTextOption option = doc.defaultTextOption();
    
    Bryant's avatar
    Bryant committed
        if ( option.wrapMode() != QTextOption::NoWrap )
        {
            option.setWrapMode( QTextOption::NoWrap );
            doc.setDefaultTextOption( option );
    
    pixhawk's avatar
    pixhawk committed
            doc.adjustSize();
        }
    
    
    Bryant's avatar
    Bryant committed
        return doc.size();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Draw the text in a clipping rectangle
    
      \param painter Painter
      \param rect Clipping rectangle
    
    Bryant's avatar
    Bryant committed
      \param flags Bitwise OR of the flags like in for QPainter::drawText()
    
    pixhawk's avatar
    pixhawk committed
      \param text Text to be rendered
    */
    
    Bryant's avatar
    Bryant committed
    void QwtRichTextEngine::draw( QPainter *painter, const QRectF &rect,
        int flags, const QString& text ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtRichTextDocument doc( text, flags, painter->font() );
        QwtPainter::drawSimpleRichText( painter, rect, flags, doc );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
       Wrap text into <div align=...> </div> tags according flags
    
       \param text Text
    
    Bryant's avatar
    Bryant committed
       \param flags Bitwise OR of the flags like in for QPainter::drawText()
    
    pixhawk's avatar
    pixhawk committed
    
       \return Tagged text
    */
    
    Bryant's avatar
    Bryant committed
    QString QwtRichTextEngine::taggedText( const QString &text, int flags ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return taggedRichText( text, flags );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Test if a string can be rendered by this text engine
    
      \param text Text to be tested
    
    Bryant's avatar
    Bryant committed
      \return Qt::mightBeRichText(text);
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtRichTextEngine::mightRender( const QString &text ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return Qt::mightBeRichText( text );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Return margins around the texts
    
      \param left Return 0
      \param right Return 0
      \param top Return 0
      \param bottom Return 0
    */
    
    Bryant's avatar
    Bryant committed
    void QwtRichTextEngine::textMargins( const QFont &, const QString &,
        double &left, double &right, double &top, double &bottom ) const
    
    pixhawk's avatar
    pixhawk committed
    {
        left = right = top = bottom = 0;
    }
    
    #endif // !QT_NO_RICHTEXT