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.
398 lines
0 B
398 lines
0 B
15 years ago
|
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||
|
* Qwt Widget Library
|
||
|
* Copyright (C) 1997 Josef Wilgen
|
||
|
* Copyright (C) 2002 Uwe Rathmann
|
||
14 years ago
|
*
|
||
15 years ago
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the Qwt License, Version 1.0
|
||
|
*****************************************************************************/
|
||
|
|
||
|
// vim: expandtab
|
||
|
|
||
|
#include <qpainter.h>
|
||
|
#include <qpalette.h>
|
||
|
#include <qmap.h>
|
||
|
#include <qlocale.h>
|
||
|
#include "qwt_math.h"
|
||
|
#include "qwt_text.h"
|
||
|
#include "qwt_painter.h"
|
||
|
#include "qwt_scale_map.h"
|
||
|
#include "qwt_scale_draw.h"
|
||
|
|
||
|
class QwtAbstractScaleDraw::PrivateData
|
||
|
{
|
||
|
public:
|
||
|
PrivateData():
|
||
|
components(Backbone | Ticks | Labels),
|
||
|
spacing(4),
|
||
14 years ago
|
minExtent(0) {
|
||
15 years ago
|
tickLength[QwtScaleDiv::MinorTick] = 4;
|
||
|
tickLength[QwtScaleDiv::MediumTick] = 6;
|
||
|
tickLength[QwtScaleDiv::MajorTick] = 8;
|
||
|
}
|
||
|
|
||
|
int components;
|
||
14 years ago
|
|
||
15 years ago
|
QwtScaleMap map;
|
||
|
QwtScaleDiv scldiv;
|
||
14 years ago
|
|
||
15 years ago
|
int spacing;
|
||
|
int tickLength[QwtScaleDiv::NTickTypes];
|
||
|
|
||
|
int minExtent;
|
||
|
|
||
|
QMap<double, QwtText> labelCache;
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
\brief Constructor
|
||
|
|
||
|
The range of the scale is initialized to [0, 100],
|
||
|
The spacing (distance between ticks and labels) is
|
||
|
set to 4, the tick lengths are set to 4,6 and 8 pixels
|
||
|
*/
|
||
|
QwtAbstractScaleDraw::QwtAbstractScaleDraw()
|
||
|
{
|
||
|
d_data = new QwtAbstractScaleDraw::PrivateData;
|
||
|
}
|
||
|
|
||
|
//! Copy constructor
|
||
|
QwtAbstractScaleDraw::QwtAbstractScaleDraw(const QwtAbstractScaleDraw &other)
|
||
|
{
|
||
|
d_data = new QwtAbstractScaleDraw::PrivateData(*other.d_data);
|
||
|
}
|
||
|
|
||
|
//! Destructor
|
||
|
QwtAbstractScaleDraw::~QwtAbstractScaleDraw()
|
||
|
{
|
||
|
delete d_data;
|
||
|
}
|
||
|
//! Assignment operator
|
||
|
QwtAbstractScaleDraw &QwtAbstractScaleDraw::operator=(const QwtAbstractScaleDraw &other)
|
||
|
{
|
||
|
*d_data = *other.d_data;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
15 years ago
|
En/Disable a component of the scale
|
||
|
|
||
|
\param component Scale component
|
||
|
\param enable On/Off
|
||
|
|
||
|
\sa QwtAbstractScaleDraw::hasComponent
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::enableComponent(
|
||
|
ScaleComponent component, bool enable)
|
||
|
{
|
||
|
if ( enable )
|
||
|
d_data->components |= component;
|
||
|
else
|
||
|
d_data->components &= ~component;
|
||
|
}
|
||
|
|
||
14 years ago
|
/*!
|
||
|
Check if a component is enabled
|
||
15 years ago
|
\sa QwtAbstractScaleDraw::enableComponent
|
||
|
*/
|
||
|
bool QwtAbstractScaleDraw::hasComponent(ScaleComponent component) const
|
||
|
{
|
||
|
return (d_data->components & component);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Change the scale division
|
||
|
\param sd New scale division
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &sd)
|
||
|
{
|
||
|
d_data->scldiv = sd;
|
||
|
d_data->map.setScaleInterval(sd.lBound(), sd.hBound());
|
||
|
d_data->labelCache.clear();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Change the transformation of the scale
|
||
|
\param transformation New scale transformation
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::setTransformation(
|
||
|
QwtScaleTransformation *transformation)
|
||
|
{
|
||
|
d_data->map.setTransformation(transformation);
|
||
|
}
|
||
|
|
||
|
//! \return Map how to translate between scale and pixel values
|
||
|
const QwtScaleMap &QwtAbstractScaleDraw::map() const
|
||
|
{
|
||
|
return d_data->map;
|
||
|
}
|
||
|
|
||
|
//! \return Map how to translate between scale and pixel values
|
||
14 years ago
|
QwtScaleMap &QwtAbstractScaleDraw::scaleMap()
|
||
15 years ago
|
{
|
||
|
return d_data->map;
|
||
|
}
|
||
|
|
||
14 years ago
|
//! \return scale division
|
||
|
const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const
|
||
|
{
|
||
|
return d_data->scldiv;
|
||
15 years ago
|
}
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
/*!
|
||
|
\brief Draw the scale
|
||
|
|
||
|
\param painter The painter
|
||
|
|
||
14 years ago
|
\param colorGroup Color group, text color is used for the labels,
|
||
15 years ago
|
foreground color for ticks and backbone
|
||
|
*/
|
||
14 years ago
|
void QwtAbstractScaleDraw::draw(QPainter *painter,
|
||
|
const QColorGroup& colorGroup) const
|
||
15 years ago
|
|
||
|
#else
|
||
|
|
||
|
/*!
|
||
|
\brief Draw the scale
|
||
|
|
||
|
\param painter The painter
|
||
|
|
||
14 years ago
|
\param palette Palette, text color is used for the labels,
|
||
15 years ago
|
foreground color for ticks and backbone
|
||
|
*/
|
||
14 years ago
|
void QwtAbstractScaleDraw::draw(QPainter *painter,
|
||
|
const QPalette& palette) const
|
||
15 years ago
|
#endif
|
||
|
{
|
||
14 years ago
|
if ( hasComponent(QwtAbstractScaleDraw::Labels) ) {
|
||
15 years ago
|
painter->save();
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
painter->setPen(colorGroup.text()); // ignore pen style
|
||
|
#else
|
||
|
painter->setPen(palette.color(QPalette::Text)); // ignore pen style
|
||
|
#endif
|
||
|
|
||
14 years ago
|
const QwtValueList &majorTicks =
|
||
15 years ago
|
d_data->scldiv.ticks(QwtScaleDiv::MajorTick);
|
||
|
|
||
14 years ago
|
for (int i = 0; i < (int)majorTicks.count(); i++) {
|
||
15 years ago
|
const double v = majorTicks[i];
|
||
|
if ( d_data->scldiv.contains(v) )
|
||
|
drawLabel(painter, majorTicks[i]);
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
14 years ago
|
if ( hasComponent(QwtAbstractScaleDraw::Ticks) ) {
|
||
15 years ago
|
painter->save();
|
||
|
|
||
|
QPen pen = painter->pen();
|
||
|
#if QT_VERSION < 0x040000
|
||
|
pen.setColor(colorGroup.foreground());
|
||
|
#else
|
||
|
pen.setColor(palette.color(QPalette::Foreground));
|
||
|
#endif
|
||
|
painter->setPen(pen);
|
||
|
|
||
14 years ago
|
for ( int tickType = QwtScaleDiv::MinorTick;
|
||
|
tickType < QwtScaleDiv::NTickTypes; tickType++ ) {
|
||
15 years ago
|
const QwtValueList &ticks = d_data->scldiv.ticks(tickType);
|
||
14 years ago
|
for (int i = 0; i < (int)ticks.count(); i++) {
|
||
15 years ago
|
const double v = ticks[i];
|
||
|
if ( d_data->scldiv.contains(v) )
|
||
|
drawTick(painter, v, d_data->tickLength[tickType]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
14 years ago
|
if ( hasComponent(QwtAbstractScaleDraw::Backbone) ) {
|
||
15 years ago
|
painter->save();
|
||
|
|
||
|
QPen pen = painter->pen();
|
||
|
#if QT_VERSION < 0x040000
|
||
|
pen.setColor(colorGroup.foreground());
|
||
|
#else
|
||
|
pen.setColor(palette.color(QPalette::Foreground));
|
||
|
#endif
|
||
|
painter->setPen(pen);
|
||
|
|
||
|
drawBackbone(painter);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the spacing between tick and labels
|
||
|
|
||
|
The spacing is the distance between ticks and labels.
|
||
|
The default spacing is 4 pixels.
|
||
|
|
||
|
\param spacing Spacing
|
||
|
|
||
|
\sa QwtAbstractScaleDraw::spacing
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::setSpacing(int spacing)
|
||
|
{
|
||
|
if ( spacing < 0 )
|
||
|
spacing = 0;
|
||
|
|
||
|
d_data->spacing = spacing;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Get the spacing
|
||
|
|
||
|
The spacing is the distance between ticks and labels.
|
||
|
The default spacing is 4 pixels.
|
||
|
|
||
|
\sa QwtAbstractScaleDraw::setSpacing
|
||
|
*/
|
||
|
int QwtAbstractScaleDraw::spacing() const
|
||
|
{
|
||
|
return d_data->spacing;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set a minimum for the extent
|
||
|
|
||
|
The extent is calculated from the coomponents of the
|
||
|
scale draw. In situations, where the labels are
|
||
|
changing and the layout depends on the extent (f.e scrolling
|
||
|
a scale), setting an upper limit as minimum extent will
|
||
|
avoid jumps of the layout.
|
||
|
|
||
|
\param minExtent Minimum extent
|
||
|
|
||
|
\sa extent(), minimumExtent()
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::setMinimumExtent(int minExtent)
|
||
|
{
|
||
|
if ( minExtent < 0 )
|
||
|
minExtent = 0;
|
||
|
|
||
|
d_data->minExtent = minExtent;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Get the minimum extent
|
||
|
\sa extent(), setMinimumExtent()
|
||
|
*/
|
||
|
int QwtAbstractScaleDraw::minimumExtent() const
|
||
|
{
|
||
|
return d_data->minExtent;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Set the length of the ticks
|
||
14 years ago
|
|
||
15 years ago
|
\param tickType Tick type
|
||
|
\param length New length
|
||
|
|
||
|
\warning the length is limited to [0..1000]
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::setTickLength(
|
||
|
QwtScaleDiv::TickType tickType, int length)
|
||
|
{
|
||
14 years ago
|
if ( tickType < QwtScaleDiv::MinorTick ||
|
||
|
tickType > QwtScaleDiv::MajorTick ) {
|
||
15 years ago
|
return;
|
||
|
}
|
||
|
|
||
|
if ( length < 0 )
|
||
|
length = 0;
|
||
|
|
||
|
const int maxTickLen = 1000;
|
||
|
if ( length > maxTickLen )
|
||
|
length = 1000;
|
||
|
|
||
|
d_data->tickLength[tickType] = length;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Return the length of the ticks
|
||
|
|
||
14 years ago
|
\sa QwtAbstractScaleDraw::setTickLength,
|
||
15 years ago
|
QwtAbstractScaleDraw::majTickLength
|
||
|
*/
|
||
|
int QwtAbstractScaleDraw::tickLength(QwtScaleDiv::TickType tickType) const
|
||
|
{
|
||
14 years ago
|
if ( tickType < QwtScaleDiv::MinorTick ||
|
||
|
tickType > QwtScaleDiv::MajorTick ) {
|
||
15 years ago
|
return 0;
|
||
|
}
|
||
|
|
||
|
return d_data->tickLength[tickType];
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
The same as QwtAbstractScaleDraw::tickLength(QwtScaleDiv::MajorTick).
|
||
|
*/
|
||
|
int QwtAbstractScaleDraw::majTickLength() const
|
||
|
{
|
||
|
return d_data->tickLength[QwtScaleDiv::MajorTick];
|
||
|
}
|
||
|
|
||
|
/*!
|
||
14 years ago
|
\brief Convert a value into its representing label
|
||
15 years ago
|
|
||
14 years ago
|
The value is converted to a plain text using
|
||
15 years ago
|
QLocale::system().toString(value).
|
||
|
This method is often overloaded by applications to have individual
|
||
|
labels.
|
||
|
|
||
|
\param value Value
|
||
|
\return Label string.
|
||
|
*/
|
||
|
QwtText QwtAbstractScaleDraw::label(double value) const
|
||
|
{
|
||
|
return QLocale::system().toString(value);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Convert a value into its representing label and cache it.
|
||
|
|
||
|
The conversion between value and label is called very often
|
||
|
in the layout and painting code. Unfortunately the
|
||
|
calculation of the label sizes might be slow (really slow
|
||
14 years ago
|
for rich text in Qt4), so it's necessary to cache the labels.
|
||
15 years ago
|
|
||
|
\param font Font
|
||
|
\param value Value
|
||
|
|
||
|
\return Tick label
|
||
|
*/
|
||
|
const QwtText &QwtAbstractScaleDraw::tickLabel(
|
||
|
const QFont &font, double value) const
|
||
|
{
|
||
|
QMap<double, QwtText>::const_iterator it = d_data->labelCache.find(value);
|
||
14 years ago
|
if ( it == d_data->labelCache.end() ) {
|
||
15 years ago
|
QwtText lbl = label(value);
|
||
|
lbl.setRenderFlags(0);
|
||
|
lbl.setLayoutAttribute(QwtText::MinimumLayout);
|
||
|
|
||
|
(void)lbl.textSize(font); // initialize the internal cache
|
||
|
|
||
|
it = d_data->labelCache.insert(value, lbl);
|
||
|
}
|
||
|
|
||
|
return (*it);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Invalidate the cache used by QwtAbstractScaleDraw::tickLabel
|
||
|
|
||
|
The cache is invalidated, when a new QwtScaleDiv is set. If
|
||
|
the labels need to be changed. while the same QwtScaleDiv is set,
|
||
|
QwtAbstractScaleDraw::invalidateCache needs to be called manually.
|
||
|
*/
|
||
|
void QwtAbstractScaleDraw::invalidateCache()
|
||
|
{
|
||
|
d_data->labelCache.clear();
|
||
|
}
|