You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
7.4 KiB
285 lines
7.4 KiB
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** |
|
* Qwt Widget Library |
|
* Copyright (C) 1997 Josef Wilgen |
|
* Copyright (C) 2002 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 |
|
*****************************************************************************/ |
|
|
|
#include <qapplication.h> |
|
#include <qdesktopwidget.h> |
|
#include <qpaintdevice.h> |
|
#include <qpainter.h> |
|
#include "qwt_legend.h" |
|
#include "qwt_legend_item.h" |
|
#include "qwt_scale_map.h" |
|
#include "qwt_plot_rasteritem.h" |
|
|
|
class QwtPlotRasterItem::PrivateData |
|
{ |
|
public: |
|
PrivateData(): |
|
alpha(-1) { |
|
cache.policy = QwtPlotRasterItem::NoCache; |
|
} |
|
|
|
int alpha; |
|
|
|
struct ImageCache { |
|
QwtPlotRasterItem::CachePolicy policy; |
|
QwtDoubleRect rect; |
|
QSize size; |
|
QImage image; |
|
} cache; |
|
}; |
|
|
|
static QImage toRgba(const QImage& image, int alpha) |
|
{ |
|
if ( alpha < 0 || alpha >= 255 ) |
|
return image; |
|
|
|
#if QT_VERSION < 0x040000 |
|
QImage alphaImage(image.size(), 32); |
|
alphaImage.setAlphaBuffer(true); |
|
#else |
|
QImage alphaImage(image.size(), QImage::Format_ARGB32); |
|
#endif |
|
|
|
const QRgb mask1 = qRgba(0, 0, 0, alpha); |
|
const QRgb mask2 = qRgba(255, 255, 255, 0); |
|
const QRgb mask3 = qRgba(0, 0, 0, 255); |
|
|
|
const int w = image.size().width(); |
|
const int h = image.size().height(); |
|
|
|
if ( image.depth() == 8 ) { |
|
for ( int y = 0; y < h; y++ ) { |
|
QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y); |
|
const unsigned char *line = image.scanLine(y); |
|
|
|
for ( int x = 0; x < w; x++ ) |
|
*alphaLine++ = (image.color(*line++) & mask2) | mask1; |
|
} |
|
} else if ( image.depth() == 32 ) { |
|
for ( int y = 0; y < h; y++ ) { |
|
QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y); |
|
const QRgb* line = (const QRgb*) image.scanLine(y); |
|
|
|
for ( int x = 0; x < w; x++ ) { |
|
const QRgb rgb = *line++; |
|
if ( rgb & mask3 ) // alpha != 0 |
|
*alphaLine++ = (rgb & mask2) | mask1; |
|
else |
|
*alphaLine++ = rgb; |
|
} |
|
} |
|
} |
|
|
|
return alphaImage; |
|
} |
|
|
|
//! Constructor |
|
QwtPlotRasterItem::QwtPlotRasterItem(const QString& title): |
|
QwtPlotItem(QwtText(title)) |
|
{ |
|
init(); |
|
} |
|
|
|
//! Constructor |
|
QwtPlotRasterItem::QwtPlotRasterItem(const QwtText& title): |
|
QwtPlotItem(title) |
|
{ |
|
init(); |
|
} |
|
|
|
//! Destructor |
|
QwtPlotRasterItem::~QwtPlotRasterItem() |
|
{ |
|
delete d_data; |
|
} |
|
|
|
void QwtPlotRasterItem::init() |
|
{ |
|
d_data = new PrivateData(); |
|
|
|
setItemAttribute(QwtPlotItem::AutoScale, true); |
|
setItemAttribute(QwtPlotItem::Legend, false); |
|
|
|
setZ(8.0); |
|
} |
|
|
|
/*! |
|
\brief Set an alpha value for the raster data |
|
|
|
Often a plot has several types of raster data organized in layers. |
|
( f.e a geographical map, with weather statistics ). |
|
Using setAlpha() raster items can be stacked easily. |
|
|
|
The alpha value is a value [0, 255] to |
|
control the transparency of the image. 0 represents a fully |
|
transparent color, while 255 represents a fully opaque color. |
|
|
|
\param alpha Alpha value |
|
|
|
- alpha >= 0\n |
|
All alpha values of the pixels returned by renderImage() will be set to |
|
alpha, beside those with an alpha value of 0 (invalid pixels). |
|
- alpha < 0 |
|
The alpha values returned by renderImage() are not changed. |
|
|
|
The default alpha value is -1. |
|
|
|
\sa alpha() |
|
*/ |
|
void QwtPlotRasterItem::setAlpha(int alpha) |
|
{ |
|
if ( alpha < 0 ) |
|
alpha = -1; |
|
|
|
if ( alpha > 255 ) |
|
alpha = 255; |
|
|
|
if ( alpha != d_data->alpha ) { |
|
d_data->alpha = alpha; |
|
|
|
itemChanged(); |
|
} |
|
} |
|
|
|
/*! |
|
\return Alpha value of the raster item |
|
\sa setAlpha() |
|
*/ |
|
int QwtPlotRasterItem::alpha() const |
|
{ |
|
return d_data->alpha; |
|
} |
|
|
|
/*! |
|
Change the cache policy |
|
|
|
The default policy is NoCache |
|
|
|
\param policy Cache policy |
|
\sa CachePolicy, cachePolicy() |
|
*/ |
|
void QwtPlotRasterItem::setCachePolicy( |
|
QwtPlotRasterItem::CachePolicy policy) |
|
{ |
|
if ( d_data->cache.policy != policy ) { |
|
d_data->cache.policy = policy; |
|
|
|
invalidateCache(); |
|
itemChanged(); |
|
} |
|
} |
|
|
|
/*! |
|
\return Cache policy |
|
\sa CachePolicy, setCachePolicy() |
|
*/ |
|
QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const |
|
{ |
|
return d_data->cache.policy; |
|
} |
|
|
|
/*! |
|
Invalidate the paint cache |
|
\sa setCachePolicy |
|
*/ |
|
void QwtPlotRasterItem::invalidateCache() |
|
{ |
|
d_data->cache.image = QImage(); |
|
d_data->cache.rect = QwtDoubleRect(); |
|
d_data->cache.size = QSize(); |
|
} |
|
|
|
/*! |
|
\brief Returns the recommended raster for a given rect. |
|
|
|
F.e the raster hint can be used to limit the resolution of |
|
the image that is rendered. |
|
|
|
The default implementation returns an invalid size (QSize()), |
|
what means: no hint. |
|
*/ |
|
QSize QwtPlotRasterItem::rasterHint(const QwtDoubleRect &) const |
|
{ |
|
return QSize(); |
|
} |
|
|
|
/*! |
|
\brief Draw the raster data |
|
\param painter Painter |
|
\param xMap X-Scale Map |
|
\param yMap Y-Scale Map |
|
\param canvasRect Contents rect of the plot canvas |
|
*/ |
|
void QwtPlotRasterItem::draw(QPainter *painter, |
|
const QwtScaleMap &xMap, const QwtScaleMap &yMap, |
|
const QRect &canvasRect) const |
|
{ |
|
if ( canvasRect.isEmpty() || d_data->alpha == 0 ) |
|
return; |
|
|
|
QwtDoubleRect area = invTransform(xMap, yMap, canvasRect); |
|
if ( boundingRect().isValid() ) |
|
area &= boundingRect(); |
|
|
|
const QRect paintRect = transform(xMap, yMap, area); |
|
if ( !paintRect.isValid() ) |
|
return; |
|
|
|
QImage image; |
|
|
|
bool doCache = true; |
|
if ( painter->device()->devType() == QInternal::Printer |
|
|| painter->device()->devType() == QInternal::Picture ) { |
|
doCache = false; |
|
} |
|
|
|
if ( !doCache || d_data->cache.policy == NoCache ) { |
|
image = renderImage(xMap, yMap, area); |
|
if ( d_data->alpha >= 0 && d_data->alpha < 255 ) |
|
image = toRgba(image, d_data->alpha); |
|
|
|
} else if ( d_data->cache.policy == PaintCache ) { |
|
if ( d_data->cache.image.isNull() || d_data->cache.rect != area |
|
|| d_data->cache.size != paintRect.size() ) { |
|
d_data->cache.image = renderImage(xMap, yMap, area); |
|
d_data->cache.rect = area; |
|
d_data->cache.size = paintRect.size(); |
|
} |
|
|
|
image = d_data->cache.image; |
|
if ( d_data->alpha >= 0 && d_data->alpha < 255 ) |
|
image = toRgba(image, d_data->alpha); |
|
} else if ( d_data->cache.policy == ScreenCache ) { |
|
const QSize screenSize = |
|
QApplication::desktop()->screenGeometry().size(); |
|
|
|
if ( paintRect.width() > screenSize.width() || |
|
paintRect.height() > screenSize.height() ) { |
|
image = renderImage(xMap, yMap, area); |
|
} else { |
|
if ( d_data->cache.image.isNull() || d_data->cache.rect != area ) { |
|
QwtScaleMap cacheXMap = xMap; |
|
cacheXMap.setPaintInterval( 0, screenSize.width()); |
|
|
|
QwtScaleMap cacheYMap = yMap; |
|
cacheYMap.setPaintInterval(screenSize.height(), 0); |
|
|
|
d_data->cache.image = renderImage( |
|
cacheXMap, cacheYMap, area); |
|
d_data->cache.rect = area; |
|
d_data->cache.size = paintRect.size(); |
|
} |
|
|
|
image = d_data->cache.image; |
|
} |
|
image = toRgba(image, d_data->alpha); |
|
} |
|
|
|
painter->drawImage(paintRect, image); |
|
}
|
|
|