~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.0.2/src/qwt_text_engine.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2007-10-05 15:20:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071005152041-qmybqh4fj9jejyo2
Tags: 5.0.2-2
* Handle nostrip build option. (Closes: #437877)
* Build libqwt5-doc package in binary-indep target. (Closes: #443110)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 
2
 * Qwt Widget Library
 
3
 * Copyright (C) 1997   Josef Wilgen
 
4
 * Copyright (C) 2003   Uwe Rathmann
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the Qwt License, Version 1.0
 
8
 *****************************************************************************/
 
9
 
 
10
// vim: expandtab
 
11
 
 
12
#include <qpainter.h>
 
13
#include <qpixmap.h>
 
14
#include <qimage.h>
 
15
#include <qmap.h>
 
16
#include <qwidget.h>
 
17
#include "qwt_math.h"
 
18
#include "qwt_painter.h"
 
19
#include "qwt_text_engine.h"
 
20
 
 
21
#if QT_VERSION < 0x040000
 
22
 
 
23
#include <qsimplerichtext.h>
 
24
#include <qstylesheet.h>
 
25
 
 
26
class QwtRichTextDocument: public QSimpleRichText
 
27
{
 
28
public:
 
29
    QwtRichTextDocument(const QString &text, const QFont &font):
 
30
        QSimpleRichText(text, font)
 
31
    {
 
32
    }
 
33
};
 
34
 
 
35
#else // QT_VERSION >= 0x040000
 
36
 
 
37
#if QT_VERSION < 0x040200
 
38
#define USE_LABEL 1
 
39
#endif
 
40
 
 
41
#ifdef USE_LABEL
 
42
#include <qlabel.h>
 
43
#else
 
44
#include <qtextobject.h>
 
45
#endif
 
46
#include <qtextdocument.h>
 
47
#include <qabstracttextdocumentlayout.h>
 
48
 
 
49
class QwtRichTextDocument: public QTextDocument
 
50
{
 
51
public:
 
52
    QwtRichTextDocument(const QString &text, const QFont &font)
 
53
    {
 
54
        setUndoRedoEnabled(false);
 
55
        setDefaultFont(font);
 
56
        setHtml(text);
 
57
 
 
58
        // make sure we have a document layout
 
59
        (void)documentLayout();
 
60
    }
 
61
};
 
62
 
 
63
#endif
 
64
 
 
65
class QwtPlainTextEngine::PrivateData
 
66
{
 
67
public:
 
68
    int effectiveAscent(const QFont &font) const
 
69
    {
 
70
        const QString fontKey = font.key();
 
71
 
 
72
        QMap<QString, int>::const_iterator it = 
 
73
            d_ascentCache.find(fontKey);
 
74
        if ( it == d_ascentCache.end() )
 
75
        {
 
76
            int ascent = findAscent(font);
 
77
            it = d_ascentCache.insert(fontKey, ascent);
 
78
        }
 
79
 
 
80
        return (*it);
 
81
    }
 
82
 
 
83
private:
 
84
    int findAscent(const QFont &font) const
 
85
    {
 
86
        static const QString dummy("E");
 
87
        static const QColor white(Qt::white);
 
88
 
 
89
        const QFontMetrics fm(font);
 
90
        QPixmap pm(fm.width(dummy), fm.height()); 
 
91
        pm.fill(white);
 
92
 
 
93
        QPainter p(&pm);
 
94
        p.setFont(font);  
 
95
        p.drawText(0, 0,  pm.width(), pm.height(), 0, dummy);
 
96
        p.end();
 
97
 
 
98
    #if QT_VERSION < 0x040000
 
99
        const QImage img = pm.convertToImage();
 
100
    #else
 
101
        const QImage img = pm.toImage();
 
102
    #endif
 
103
 
 
104
        int row = 0;
 
105
        for ( row = 0; row < img.height(); row++ )
 
106
        {   
 
107
            const QRgb *line = (const QRgb *)img.scanLine(row);
 
108
 
 
109
            const int w = pm.width();
 
110
            for ( int col = 0; col < w; col++ )
 
111
            {   
 
112
                if ( line[col] != white.rgb() )
 
113
                    return fm.ascent() - row + 1;
 
114
            }
 
115
        }
 
116
 
 
117
        return fm.ascent();
 
118
    }   
 
119
 
 
120
    mutable QMap<QString, int> d_ascentCache;
 
121
};
 
122
 
 
123
//! Constructor
 
124
QwtTextEngine::QwtTextEngine()
 
125
{
 
126
}
 
127
 
 
128
//! Destructor
 
129
QwtTextEngine::~QwtTextEngine()
 
130
{
 
131
}
 
132
 
 
133
//! Constructor
 
134
QwtPlainTextEngine::QwtPlainTextEngine()
 
135
{
 
136
    d_data = new PrivateData;
 
137
}
 
138
 
 
139
//! Destructor
 
140
QwtPlainTextEngine::~QwtPlainTextEngine()
 
141
{
 
142
    delete d_data;
 
143
}
 
144
 
 
145
/*!
 
146
   Find the height for a given width
 
147
 
 
148
   \param font Font of the text
 
149
   \param flags Bitwise OR of the flags used like in QPainter::drawText
 
150
   \param text Text to be rendered
 
151
   \param width Width  
 
152
 
 
153
   \return Calculated height
 
154
*/
 
155
int QwtPlainTextEngine::heightForWidth(const QFont& font, int flags,
 
156
        const QString& text, int width) const
 
157
{
 
158
    const QFontMetrics fm(font);
 
159
    const QRect rect = fm.boundingRect(
 
160
        0, 0, width, QWIDGETSIZE_MAX, flags, text);
 
161
 
 
162
    return rect.height();
 
163
}
 
164
 
 
165
/*!
 
166
  Returns the size, that is needed to render text
 
167
 
 
168
  \param font Font of the text
 
169
  \param flags Bitwise OR of the flags used like in QPainter::drawText
 
170
  \param text Text to be rendered
 
171
 
 
172
  \return Caluclated size
 
173
*/
 
174
QSize QwtPlainTextEngine::textSize(const QFont &font,
 
175
    int flags, const QString& text) const
 
176
{
 
177
    const QFontMetrics fm(font);
 
178
    const QRect rect = fm.boundingRect(
 
179
        0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, flags, text);
 
180
 
 
181
    return rect.size();
 
182
}
 
183
 
 
184
/*!
 
185
  Return margins around the texts
 
186
 
 
187
  \param font Font of the text
 
188
  \param left Return 0
 
189
  \param right Return 0
 
190
  \param top Return value for the top margin
 
191
  \param bottom Return value for the bottom margin
 
192
*/
 
193
void QwtPlainTextEngine::textMargins(const QFont &font, const QString &,
 
194
    int &left, int &right, int &top, int &bottom) const
 
195
{
 
196
    left = right = top = 0;
 
197
 
 
198
    const QFontMetrics fm(font);
 
199
    top = fm.ascent() - d_data->effectiveAscent(font);
 
200
    bottom = fm.descent() + 1;
 
201
}
 
202
 
 
203
/*!
 
204
  \brief Draw the text in a clipping rectangle
 
205
      
 
206
  A wrapper for QPainter::drawText.
 
207
 
 
208
  \param painter Painter
 
209
  \param rect Clipping rectangle
 
210
  \param flags Bitwise OR of the flags used like in QPainter::drawText
 
211
  \param text Text to be rendered
 
212
*/
 
213
void QwtPlainTextEngine::draw(QPainter *painter, const QRect &rect,
 
214
    int flags, const QString& text) const
 
215
{
 
216
    QwtPainter::drawText(painter, rect, flags, text);
 
217
}
 
218
 
 
219
/*! 
 
220
  Test if a string can be rendered by this text engine.
 
221
  \return Always true. All texts can be rendered by QwtPlainTextEngine
 
222
*/
 
223
bool QwtPlainTextEngine::mightRender(const QString &) const
 
224
{
 
225
    return true;
 
226
}
 
227
 
 
228
#ifndef QT_NO_RICHTEXT
 
229
 
 
230
//! Constructor
 
231
QwtRichTextEngine::QwtRichTextEngine()
 
232
{
 
233
}
 
234
 
 
235
/*!
 
236
   Find the height for a given width
 
237
  
 
238
   \param font Font of the text
 
239
   \param flags Bitwise OR of the flags used like in QPainter::drawText
 
240
   \param text Text to be rendered
 
241
   \param width Width  
 
242
 
 
243
   \return Calculated height
 
244
*/
 
245
int QwtRichTextEngine::heightForWidth(const QFont& font, int flags,
 
246
        const QString& text, int width) const
 
247
{
 
248
    QwtRichTextDocument doc(taggedText(text, flags), font);
 
249
 
 
250
#if QT_VERSION < 0x040000
 
251
    doc.setWidth(width);
 
252
    const int h = doc.height();
 
253
#else
 
254
    doc.setPageSize(QSize(width, QWIDGETSIZE_MAX));
 
255
    const int h = qRound(doc.documentLayout()->documentSize().height());
 
256
#endif
 
257
    return h;
 
258
}
 
259
 
 
260
/*!
 
261
  Returns the size, that is needed to render text
 
262
  
 
263
  \param font Font of the text
 
264
  \param flags Bitwise OR of the flags used like in QPainter::drawText
 
265
  \param text Text to be rendered
 
266
 
 
267
  \return Caluclated size
 
268
*/
 
269
 
 
270
QSize QwtRichTextEngine::textSize(const QFont &font,
 
271
    int flags, const QString& text) const
 
272
{
 
273
    QwtRichTextDocument doc(taggedText(text, flags), font);
 
274
 
 
275
#if QT_VERSION < 0x040000
 
276
    doc.setWidth(QWIDGETSIZE_MAX);
 
277
 
 
278
    int w = doc.widthUsed();
 
279
    int h = doc.height();
 
280
#else
 
281
#if USE_LABEL 
 
282
    /*
 
283
      Unfortunately offering the bounding rect calculation in the
 
284
      API of QTextDocument has been forgotten in Qt <= 4.1.x. It
 
285
      is planned to come with Qt 4.2.x.
 
286
      In the meantime we need a hack with a temporary QLabel,
 
287
      to reengineer the internal calculations.
 
288
     */
 
289
 
 
290
    static int off = 0;
 
291
    static QLabel *label = NULL;
 
292
    if ( label == NULL )
 
293
    {
 
294
        label = new QLabel;
 
295
        label->hide();
 
296
 
 
297
        const char *s = "XXXXX";
 
298
        label->setText(s);
 
299
        int w1 = label->sizeHint().width();
 
300
        const QFontMetrics fm(label->font());
 
301
        int w2 = fm.width(s);
 
302
        off = w1 - w2;
 
303
    }
 
304
    label->setFont(doc.defaultFont());
 
305
    label->setText(text);
 
306
 
 
307
    int w = qwtMax(label->sizeHint().width() - off, 0);
 
308
    doc.setPageSize(QSize(w, QWIDGETSIZE_MAX));
 
309
    
 
310
    int h = qRound(doc.documentLayout()->documentSize().height());
 
311
#else
 
312
    QTextLayout *layout = doc.begin().layout();
 
313
    layout->beginLayout();
 
314
    for(qreal y = 0;;)  
 
315
    {
 
316
        QTextLine line = layout->createLine();
 
317
        if (!line.isValid())
 
318
            break;
 
319
        line.setPosition(QPointF(0, y));
 
320
        y += line.height();
 
321
    }
 
322
    layout->endLayout();
 
323
 
 
324
    int w = qRound(layout->maximumWidth());
 
325
    int h = qRound(layout->boundingRect().height());
 
326
 
 
327
    h += QFontMetrics(font).descent() + 4;
 
328
    w += 2 * 4;
 
329
#endif
 
330
#endif
 
331
 
 
332
    return QSize(w, h);
 
333
}
 
334
 
 
335
/*!
 
336
  Draw the text in a clipping rectangle
 
337
 
 
338
  \param painter Painter
 
339
  \param rect Clipping rectangle
 
340
  \param flags Bitwise OR of the flags like in for QPainter::drawText
 
341
  \param text Text to be rendered
 
342
*/
 
343
void QwtRichTextEngine::draw(QPainter *painter, const QRect &rect,
 
344
    int flags, const QString& text) const
 
345
{
 
346
    QwtRichTextDocument doc(taggedText(text, flags), painter->font());
 
347
    QwtPainter::drawSimpleRichText(painter, rect, flags, doc);
 
348
}
 
349
 
 
350
/*! 
 
351
   Wrap text into <div align=...> </div> tags according flags
 
352
 
 
353
   \param text Text
 
354
   \param flags Bitwise OR of the flags like in for QPainter::drawText
 
355
 
 
356
   \return Tagged text
 
357
*/
 
358
QString QwtRichTextEngine::taggedText(const QString &text, int flags) const
 
359
{
 
360
    QString richText = text;
 
361
 
 
362
    // By default QSimpleRichText is Qt::AlignLeft
 
363
    if (flags & Qt::AlignJustify)
 
364
    {
 
365
        richText.prepend(QString::fromLatin1("<div align=\"justify\">"));
 
366
        richText.append(QString::fromLatin1("</div>"));
 
367
    }
 
368
    else if (flags & Qt::AlignRight)
 
369
    {
 
370
        richText.prepend(QString::fromLatin1("<div align=\"right\">"));
 
371
        richText.append(QString::fromLatin1("</div>"));
 
372
    }
 
373
    else if (flags & Qt::AlignHCenter)
 
374
    {
 
375
        richText.prepend(QString::fromLatin1("<div align=\"center\">"));
 
376
        richText.append(QString::fromLatin1("</div>"));
 
377
    }
 
378
 
 
379
    return richText;
 
380
}
 
381
 
 
382
/*!
 
383
  Test if a string can be rendered by this text engine
 
384
 
 
385
  \param text Text to be tested
 
386
  \return QStyleSheet::mightBeRichText(text);
 
387
*/
 
388
bool QwtRichTextEngine::mightRender(const QString &text) const
 
389
{
 
390
#if QT_VERSION < 0x040000
 
391
    return QStyleSheet::mightBeRichText(text);
 
392
#else
 
393
    return Qt::mightBeRichText(text);
 
394
#endif
 
395
}
 
396
 
 
397
/*!
 
398
  Return margins around the texts
 
399
 
 
400
  \param left Return 0
 
401
  \param right Return 0
 
402
  \param top Return 0
 
403
  \param bottom Return 0
 
404
*/
 
405
void QwtRichTextEngine::textMargins(const QFont &, const QString &,
 
406
    int &left, int &right, int &top, int &bottom) const
 
407
{
 
408
    left = right = top = bottom = 0;
 
409
}
 
410
 
 
411
#endif // !QT_NO_RICHTEXT