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.
563 lines
12 KiB
563 lines
12 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 |
|
*****************************************************************************/ |
|
|
|
// vim: expandtab |
|
|
|
#include <qpainter.h> |
|
#include <qdrawutil.h> |
|
#include <qstyle.h> |
|
#include <qpen.h> |
|
#if QT_VERSION >= 0x040000 |
|
#include <qevent.h> |
|
#include <qstyleoption.h> |
|
#endif |
|
#include "qwt_math.h" |
|
#include "qwt_painter.h" |
|
#include "qwt_symbol.h" |
|
#include "qwt_legend_item.h" |
|
|
|
static const int ButtonFrame = 2; |
|
static const int Margin = 2; |
|
|
|
static QSize buttonShift(const QwtLegendItem *w) |
|
{ |
|
#if QT_VERSION < 0x040000 |
|
const int ph = w->style().pixelMetric( |
|
QStyle::PM_ButtonShiftHorizontal, w); |
|
const int pv = w->style().pixelMetric( |
|
QStyle::PM_ButtonShiftVertical, w); |
|
#else |
|
QStyleOption option; |
|
option.init(w); |
|
|
|
const int ph = w->style()->pixelMetric( |
|
QStyle::PM_ButtonShiftHorizontal, &option, w); |
|
const int pv = w->style()->pixelMetric( |
|
QStyle::PM_ButtonShiftVertical, &option, w); |
|
#endif |
|
return QSize(ph, pv); |
|
} |
|
|
|
class QwtLegendItem::PrivateData |
|
{ |
|
public: |
|
PrivateData(): |
|
itemMode(QwtLegend::ReadOnlyItem), |
|
isDown(false), |
|
identifierWidth(8), |
|
identifierMode(QwtLegendItem::ShowLine | QwtLegendItem::ShowText), |
|
curvePen(Qt::NoPen), |
|
spacing(Margin) { |
|
symbol = new QwtSymbol(); |
|
} |
|
|
|
~PrivateData() { |
|
delete symbol; |
|
} |
|
|
|
QwtLegend::LegendItemMode itemMode; |
|
bool isDown; |
|
|
|
int identifierWidth; |
|
int identifierMode; |
|
QwtSymbol *symbol; |
|
QPen curvePen; |
|
|
|
int spacing; |
|
}; |
|
|
|
/*! |
|
\param parent Parent widget |
|
*/ |
|
QwtLegendItem::QwtLegendItem(QWidget *parent): |
|
QwtTextLabel(parent) |
|
{ |
|
d_data = new PrivateData; |
|
init(QwtText()); |
|
} |
|
|
|
/*! |
|
\param symbol Curve symbol |
|
\param curvePen Curve pen |
|
\param text Label text |
|
\param parent Parent widget |
|
*/ |
|
QwtLegendItem::QwtLegendItem(const QwtSymbol &symbol, |
|
const QPen &curvePen, const QwtText &text, |
|
QWidget *parent): |
|
QwtTextLabel(parent) |
|
{ |
|
d_data = new PrivateData; |
|
|
|
delete d_data->symbol; |
|
d_data->symbol = symbol.clone(); |
|
|
|
d_data->curvePen = curvePen; |
|
|
|
init(text); |
|
} |
|
|
|
void QwtLegendItem::init(const QwtText &text) |
|
{ |
|
setMargin(Margin); |
|
setIndent(margin() + d_data->identifierWidth + 2 * d_data->spacing); |
|
setText(text); |
|
} |
|
|
|
//! Destructor |
|
QwtLegendItem::~QwtLegendItem() |
|
{ |
|
delete d_data; |
|
d_data = NULL; |
|
} |
|
|
|
/*! |
|
Set the text to the legend item |
|
|
|
\param text Text label |
|
\sa QwtTextLabel::text() |
|
*/ |
|
void QwtLegendItem::setText(const QwtText &text) |
|
{ |
|
const int flags = Qt::AlignLeft | Qt::AlignVCenter |
|
#if QT_VERSION < 0x040000 |
|
| Qt::WordBreak | Qt::ExpandTabs; |
|
#else |
|
| Qt::TextExpandTabs | Qt::TextWordWrap; |
|
#endif |
|
|
|
QwtText txt = text; |
|
txt.setRenderFlags(flags); |
|
|
|
QwtTextLabel::setText(txt); |
|
} |
|
|
|
/*! |
|
Set the item mode |
|
The default is QwtLegend::ReadOnlyItem |
|
|
|
\param mode Item mode |
|
\sa itemMode() |
|
*/ |
|
void QwtLegendItem::setItemMode(QwtLegend::LegendItemMode mode) |
|
{ |
|
d_data->itemMode = mode; |
|
d_data->isDown = false; |
|
|
|
#if QT_VERSION >= 0x040000 |
|
using namespace Qt; |
|
#endif |
|
setFocusPolicy(mode != QwtLegend::ReadOnlyItem ? TabFocus : NoFocus); |
|
setMargin(ButtonFrame + Margin); |
|
|
|
updateGeometry(); |
|
} |
|
|
|
/*! |
|
Return the item mode |
|
|
|
\sa setItemMode() |
|
*/ |
|
QwtLegend::LegendItemMode QwtLegendItem::itemMode() const |
|
{ |
|
return d_data->itemMode; |
|
} |
|
|
|
/*! |
|
Set identifier mode. |
|
Default is ShowLine | ShowText. |
|
\param mode Or'd values of IdentifierMode |
|
|
|
\sa identifierMode() |
|
*/ |
|
void QwtLegendItem::setIdentifierMode(int mode) |
|
{ |
|
if ( mode != d_data->identifierMode ) { |
|
d_data->identifierMode = mode; |
|
update(); |
|
} |
|
} |
|
|
|
/*! |
|
Or'd values of IdentifierMode. |
|
\sa setIdentifierMode(), IdentifierMode |
|
*/ |
|
int QwtLegendItem::identifierMode() const |
|
{ |
|
return d_data->identifierMode; |
|
} |
|
|
|
/*! |
|
Set the width for the identifier |
|
Default is 8 pixels |
|
|
|
\param width New width |
|
|
|
\sa identifierMode(), identifierWidth |
|
*/ |
|
void QwtLegendItem::setIdentfierWidth(int width) |
|
{ |
|
width = qwtMax(width, 0); |
|
if ( width != d_data->identifierWidth ) { |
|
d_data->identifierWidth = width; |
|
setIndent(margin() + d_data->identifierWidth |
|
+ 2 * d_data->spacing); |
|
} |
|
} |
|
/*! |
|
Return the width of the identifier |
|
|
|
\sa setIdentfierWidth |
|
*/ |
|
int QwtLegendItem::identifierWidth() const |
|
{ |
|
return d_data->identifierWidth; |
|
} |
|
|
|
/*! |
|
Change the spacing |
|
\param spacing Spacing |
|
\sa spacing(), identifierWidth(), QwtTextLabel::margin() |
|
*/ |
|
void QwtLegendItem::setSpacing(int spacing) |
|
{ |
|
spacing = qwtMax(spacing, 0); |
|
if ( spacing != d_data->spacing ) { |
|
d_data->spacing = spacing; |
|
setIndent(margin() + d_data->identifierWidth |
|
+ 2 * d_data->spacing); |
|
} |
|
} |
|
|
|
/*! |
|
Return the spacing |
|
\sa setSpacing(), identifierWidth(), QwtTextLabel::margin() |
|
*/ |
|
int QwtLegendItem::spacing() const |
|
{ |
|
return d_data->spacing; |
|
} |
|
|
|
/*! |
|
Set curve symbol. |
|
\param symbol Symbol |
|
|
|
\sa symbol() |
|
*/ |
|
void QwtLegendItem::setSymbol(const QwtSymbol &symbol) |
|
{ |
|
delete d_data->symbol; |
|
d_data->symbol = symbol.clone(); |
|
update(); |
|
} |
|
|
|
/*! |
|
\return The curve symbol. |
|
\sa setSymbol() |
|
*/ |
|
const QwtSymbol& QwtLegendItem::symbol() const |
|
{ |
|
return *d_data->symbol; |
|
} |
|
|
|
|
|
/*! |
|
Set curve pen. |
|
\param pen Curve pen |
|
|
|
\sa curvePen() |
|
*/ |
|
void QwtLegendItem::setCurvePen(const QPen &pen) |
|
{ |
|
if ( pen != d_data->curvePen ) { |
|
d_data->curvePen = pen; |
|
update(); |
|
} |
|
} |
|
|
|
/*! |
|
\return The curve pen. |
|
\sa setCurvePen() |
|
*/ |
|
const QPen& QwtLegendItem::curvePen() const |
|
{ |
|
return d_data->curvePen; |
|
} |
|
|
|
/*! |
|
Paint the identifier to a given rect. |
|
\param painter Painter |
|
\param rect Rect where to paint |
|
*/ |
|
void QwtLegendItem::drawIdentifier( |
|
QPainter *painter, const QRect &rect) const |
|
{ |
|
if ( rect.isEmpty() ) |
|
return; |
|
|
|
if ( (d_data->identifierMode & ShowLine ) && (d_data->curvePen.style() != Qt::NoPen) ) { |
|
painter->save(); |
|
painter->setPen(d_data->curvePen); |
|
QwtPainter::drawLine(painter, rect.left(), rect.center().y(), |
|
rect.right(), rect.center().y()); |
|
painter->restore(); |
|
} |
|
|
|
if ( (d_data->identifierMode & ShowSymbol) |
|
&& (d_data->symbol->style() != QwtSymbol::NoSymbol) ) { |
|
QSize symbolSize = |
|
QwtPainter::metricsMap().screenToLayout(d_data->symbol->size()); |
|
|
|
// scale the symbol size down if it doesn't fit into rect. |
|
|
|
if ( rect.width() < symbolSize.width() ) { |
|
const double ratio = |
|
double(symbolSize.width()) / double(rect.width()); |
|
symbolSize.setWidth(rect.width()); |
|
symbolSize.setHeight(qRound(symbolSize.height() / ratio)); |
|
} |
|
if ( rect.height() < symbolSize.height() ) { |
|
const double ratio = |
|
double(symbolSize.width()) / double(rect.width()); |
|
symbolSize.setHeight(rect.height()); |
|
symbolSize.setWidth(qRound(symbolSize.width() / ratio)); |
|
} |
|
|
|
QRect symbolRect; |
|
symbolRect.setSize(symbolSize); |
|
symbolRect.moveCenter(rect.center()); |
|
|
|
painter->save(); |
|
painter->setBrush(d_data->symbol->brush()); |
|
painter->setPen(d_data->symbol->pen()); |
|
d_data->symbol->draw(painter, symbolRect); |
|
painter->restore(); |
|
} |
|
} |
|
|
|
/*! |
|
Draw the legend item to a given rect. |
|
\param painter Painter |
|
\param rect Rect where to paint the button |
|
*/ |
|
|
|
void QwtLegendItem::drawItem(QPainter *painter, const QRect &rect) const |
|
{ |
|
painter->save(); |
|
|
|
const QwtMetricsMap &map = QwtPainter::metricsMap(); |
|
|
|
const int m = map.screenToLayoutX(margin()); |
|
const int spacing = map.screenToLayoutX(d_data->spacing); |
|
const int identifierWidth = map.screenToLayoutX(d_data->identifierWidth); |
|
|
|
const QRect identifierRect(rect.x() + m, rect.y(), |
|
identifierWidth, rect.height()); |
|
drawIdentifier(painter, identifierRect); |
|
|
|
// Label |
|
|
|
QRect titleRect = rect; |
|
titleRect.setX(identifierRect.right() + 2 * spacing); |
|
|
|
text().draw(painter, titleRect); |
|
|
|
painter->restore(); |
|
} |
|
|
|
//! Paint event |
|
void QwtLegendItem::paintEvent(QPaintEvent *e) |
|
{ |
|
const QRect cr = contentsRect(); |
|
|
|
QPainter painter(this); |
|
painter.setClipRegion(e->region()); |
|
|
|
if ( d_data->isDown ) { |
|
qDrawWinButton(&painter, 0, 0, width(), height(), |
|
#if QT_VERSION < 0x040000 |
|
colorGroup(), |
|
#else |
|
palette(), |
|
#endif |
|
true); |
|
} |
|
|
|
painter.save(); |
|
|
|
if ( d_data->isDown ) { |
|
const QSize shiftSize = buttonShift(this); |
|
painter.translate(shiftSize.width(), shiftSize.height()); |
|
} |
|
|
|
painter.setClipRect(cr); |
|
|
|
drawContents(&painter); |
|
|
|
QRect rect = cr; |
|
rect.setX(rect.x() + margin()); |
|
if ( d_data->itemMode != QwtLegend::ReadOnlyItem ) |
|
rect.setX(rect.x() + ButtonFrame); |
|
|
|
rect.setWidth(d_data->identifierWidth); |
|
|
|
drawIdentifier(&painter, rect); |
|
|
|
painter.restore(); |
|
} |
|
|
|
//! Handle mouse press events |
|
void QwtLegendItem::mousePressEvent(QMouseEvent *e) |
|
{ |
|
if ( e->button() == Qt::LeftButton ) { |
|
switch(d_data->itemMode) { |
|
case QwtLegend::ClickableItem: { |
|
setDown(true); |
|
return; |
|
} |
|
case QwtLegend::CheckableItem: { |
|
setDown(!isDown()); |
|
return; |
|
} |
|
default: |
|
; |
|
} |
|
} |
|
QwtTextLabel::mousePressEvent(e); |
|
} |
|
|
|
//! Handle mouse release events |
|
void QwtLegendItem::mouseReleaseEvent(QMouseEvent *e) |
|
{ |
|
if ( e->button() == Qt::LeftButton ) { |
|
switch(d_data->itemMode) { |
|
case QwtLegend::ClickableItem: { |
|
setDown(false); |
|
return; |
|
} |
|
case QwtLegend::CheckableItem: { |
|
return; // do nothing, but accept |
|
} |
|
default: |
|
; |
|
} |
|
} |
|
QwtTextLabel::mouseReleaseEvent(e); |
|
} |
|
|
|
//! Handle key press events |
|
void QwtLegendItem::keyPressEvent(QKeyEvent *e) |
|
{ |
|
if ( e->key() == Qt::Key_Space ) { |
|
switch(d_data->itemMode) { |
|
case QwtLegend::ClickableItem: { |
|
if ( !e->isAutoRepeat() ) |
|
setDown(true); |
|
return; |
|
} |
|
case QwtLegend::CheckableItem: { |
|
if ( !e->isAutoRepeat() ) |
|
setDown(!isDown()); |
|
return; |
|
} |
|
default: |
|
; |
|
} |
|
} |
|
|
|
QwtTextLabel::keyPressEvent(e); |
|
} |
|
|
|
//! Handle key release events |
|
void QwtLegendItem::keyReleaseEvent(QKeyEvent *e) |
|
{ |
|
if ( e->key() == Qt::Key_Space ) { |
|
switch(d_data->itemMode) { |
|
case QwtLegend::ClickableItem: { |
|
if ( !e->isAutoRepeat() ) |
|
setDown(false); |
|
return; |
|
} |
|
case QwtLegend::CheckableItem: { |
|
return; // do nothing, but accept |
|
} |
|
default: |
|
; |
|
} |
|
} |
|
|
|
QwtTextLabel::keyReleaseEvent(e); |
|
} |
|
|
|
/*! |
|
Check/Uncheck a the item |
|
|
|
\param on check/uncheck |
|
\sa setItemMode() |
|
*/ |
|
void QwtLegendItem::setChecked(bool on) |
|
{ |
|
if ( d_data->itemMode == QwtLegend::CheckableItem ) { |
|
const bool isBlocked = signalsBlocked(); |
|
blockSignals(true); |
|
|
|
setDown(on); |
|
|
|
blockSignals(isBlocked); |
|
} |
|
} |
|
|
|
//! Return true, if the item is checked |
|
bool QwtLegendItem::isChecked() const |
|
{ |
|
return d_data->itemMode == QwtLegend::CheckableItem && isDown(); |
|
} |
|
|
|
//! Set the item being down |
|
void QwtLegendItem::setDown(bool down) |
|
{ |
|
if ( down == d_data->isDown ) |
|
return; |
|
|
|
d_data->isDown = down; |
|
update(); |
|
|
|
if ( d_data->itemMode == QwtLegend::ClickableItem ) { |
|
if ( d_data->isDown ) |
|
emit pressed(); |
|
else { |
|
emit released(); |
|
emit clicked(); |
|
} |
|
} |
|
|
|
if ( d_data->itemMode == QwtLegend::CheckableItem ) |
|
emit checked(d_data->isDown); |
|
} |
|
|
|
//! Return true, if the item is down |
|
bool QwtLegendItem::isDown() const |
|
{ |
|
return d_data->isDown; |
|
} |
|
|
|
//! Return a size hint |
|
QSize QwtLegendItem::sizeHint() const |
|
{ |
|
QSize sz = QwtTextLabel::sizeHint(); |
|
if ( d_data->itemMode != QwtLegend::ReadOnlyItem ) |
|
sz += buttonShift(this); |
|
|
|
return sz; |
|
} |
|
|
|
void QwtLegendItem::drawText(QPainter *painter, const QRect &rect) |
|
{ |
|
QwtTextLabel::drawText(painter, rect); |
|
}
|
|
|