|
After Width: | Height: | Size: 216 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,48 @@
|
|||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += printsupport
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): CONFIG += c++11
|
||||||
|
#lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11
|
||||||
|
|
||||||
|
#将当前目录加入到头文件路径
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEFINES += qcustomplot
|
||||||
|
|
||||||
|
#引入平滑曲线类
|
||||||
|
HEADERS += $$PWD/smoothcurve.h
|
||||||
|
SOURCES += $$PWD/smoothcurve.cpp
|
||||||
|
|
||||||
|
#没有定义任何版本则默认采用2.0
|
||||||
|
!contains(DEFINES, qcustomplot_v1_3) {
|
||||||
|
!contains(DEFINES, qcustomplot_v2_0) {
|
||||||
|
!contains(DEFINES, qcustomplot_v2_1) {
|
||||||
|
DEFINES += qcustomplot_v2_0
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#定义了2.0版本在Qt5以上采用2.1
|
||||||
|
contains(DEFINES, qcustomplot_v2_0) {
|
||||||
|
!contains(DEFINES, qcustomplot_v2_1) {
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
|
DEFINES -= qcustomplot_v1_3
|
||||||
|
DEFINES -= qcustomplot_v2_0
|
||||||
|
DEFINES += qcustomplot_v2_1
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#根据定义的版本引入文件
|
||||||
|
contains(DEFINES, qcustomplot_v1_3) {
|
||||||
|
INCLUDEPATH += $$PWD/v1_3
|
||||||
|
HEADERS += $$PWD/v1_3/qcustomplot.h
|
||||||
|
SOURCES += $$PWD/v1_3/qcustomplot.cpp
|
||||||
|
} else {
|
||||||
|
contains(DEFINES, qcustomplot_v2_0) {
|
||||||
|
INCLUDEPATH += $$PWD/v2_0
|
||||||
|
HEADERS += $$PWD/v2_0/qcustomplot.h
|
||||||
|
SOURCES += $$PWD/v2_0/qcustomplot.cpp
|
||||||
|
} else {
|
||||||
|
INCLUDEPATH += $$PWD/v2_1
|
||||||
|
#引入对应修复不支持Qt6的头文件
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 5) {
|
||||||
|
HEADERS += $$PWD/v2_1_6/qcustomplot.h
|
||||||
|
} else {
|
||||||
|
HEADERS += $$PWD/v2_1/qcustomplot.h
|
||||||
|
}
|
||||||
|
SOURCES += $$PWD/v2_1/qcustomplot.cpp
|
||||||
|
}}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
CONFIG += C++11
|
||||||
|
HEADERS += $$PWD/qhotkey.h
|
||||||
|
HEADERS += $$PWD/qhotkey_p.h
|
||||||
|
SOURCES += $$PWD/qhotkey.cpp
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
LIBS += -luser32
|
||||||
|
SOURCES += $$PWD/qhotkey_win.cpp
|
||||||
|
}
|
||||||
|
|
||||||
|
unix:!macx {
|
||||||
|
QT += x11extras
|
||||||
|
LIBS += -lX11
|
||||||
|
SOURCES += $$PWD/qhotkey_x11.cpp
|
||||||
|
}
|
||||||
|
|
||||||
|
macx {
|
||||||
|
LIBS += -framework Carbon
|
||||||
|
SOURCES += $$PWD/qhotkey_mac.cpp
|
||||||
|
}
|
||||||
@ -0,0 +1,198 @@
|
|||||||
|
QT += core gui
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport concurrent
|
||||||
|
|
||||||
|
DEFINES += QWT_NO_SVG QWT_NO_OPENGL
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/qwt.h \
|
||||||
|
$$PWD/qwt_abstract_legend.h \
|
||||||
|
$$PWD/qwt_abstract_scale.h \
|
||||||
|
$$PWD/qwt_abstract_scale_draw.h \
|
||||||
|
$$PWD/qwt_abstract_slider.h \
|
||||||
|
$$PWD/qwt_analog_clock.h \
|
||||||
|
$$PWD/qwt_arrow_button.h \
|
||||||
|
$$PWD/qwt_clipper.h \
|
||||||
|
$$PWD/qwt_color_map.h \
|
||||||
|
$$PWD/qwt_column_symbol.h \
|
||||||
|
$$PWD/qwt_compass.h \
|
||||||
|
$$PWD/qwt_compass_rose.h \
|
||||||
|
$$PWD/qwt_compat.h \
|
||||||
|
$$PWD/qwt_counter.h \
|
||||||
|
$$PWD/qwt_curve_fitter.h \
|
||||||
|
$$PWD/qwt_date.h \
|
||||||
|
$$PWD/qwt_date_scale_draw.h \
|
||||||
|
$$PWD/qwt_date_scale_engine.h \
|
||||||
|
$$PWD/qwt_dial.h \
|
||||||
|
$$PWD/qwt_dial_needle.h \
|
||||||
|
$$PWD/qwt_dyngrid_layout.h \
|
||||||
|
$$PWD/qwt_event_pattern.h \
|
||||||
|
$$PWD/qwt_global.h \
|
||||||
|
$$PWD/qwt_graphic.h \
|
||||||
|
$$PWD/qwt_interval.h \
|
||||||
|
$$PWD/qwt_interval_symbol.h \
|
||||||
|
$$PWD/qwt_knob.h \
|
||||||
|
$$PWD/qwt_legend.h \
|
||||||
|
$$PWD/qwt_legend_data.h \
|
||||||
|
$$PWD/qwt_legend_label.h \
|
||||||
|
$$PWD/qwt_magnifier.h \
|
||||||
|
$$PWD/qwt_math.h \
|
||||||
|
$$PWD/qwt_matrix_raster_data.h \
|
||||||
|
$$PWD/qwt_null_paintdevice.h \
|
||||||
|
$$PWD/qwt_painter.h \
|
||||||
|
$$PWD/qwt_painter_command.h \
|
||||||
|
$$PWD/qwt_panner.h \
|
||||||
|
$$PWD/qwt_picker.h \
|
||||||
|
$$PWD/qwt_picker_machine.h \
|
||||||
|
$$PWD/qwt_pixel_matrix.h \
|
||||||
|
$$PWD/qwt_plot.h \
|
||||||
|
$$PWD/qwt_plot_abstract_barchart.h \
|
||||||
|
$$PWD/qwt_plot_barchart.h \
|
||||||
|
$$PWD/qwt_plot_canvas.h \
|
||||||
|
$$PWD/qwt_plot_curve.h \
|
||||||
|
$$PWD/qwt_plot_dict.h \
|
||||||
|
$$PWD/qwt_plot_directpainter.h \
|
||||||
|
$$PWD/qwt_plot_grid.h \
|
||||||
|
$$PWD/qwt_plot_histogram.h \
|
||||||
|
$$PWD/qwt_plot_intervalcurve.h \
|
||||||
|
$$PWD/qwt_plot_item.h \
|
||||||
|
$$PWD/qwt_plot_layout.h \
|
||||||
|
$$PWD/qwt_plot_legenditem.h \
|
||||||
|
$$PWD/qwt_plot_magnifier.h \
|
||||||
|
$$PWD/qwt_plot_marker.h \
|
||||||
|
$$PWD/qwt_plot_multi_barchart.h \
|
||||||
|
$$PWD/qwt_plot_panner.h \
|
||||||
|
$$PWD/qwt_plot_picker.h \
|
||||||
|
$$PWD/qwt_plot_rasteritem.h \
|
||||||
|
$$PWD/qwt_plot_renderer.h \
|
||||||
|
$$PWD/qwt_plot_rescaler.h \
|
||||||
|
$$PWD/qwt_plot_scaleitem.h \
|
||||||
|
$$PWD/qwt_plot_seriesitem.h \
|
||||||
|
$$PWD/qwt_plot_shapeitem.h \
|
||||||
|
$$PWD/qwt_plot_spectrocurve.h \
|
||||||
|
$$PWD/qwt_plot_spectrogram.h \
|
||||||
|
$$PWD/qwt_plot_textlabel.h \
|
||||||
|
$$PWD/qwt_plot_tradingcurve.h \
|
||||||
|
$$PWD/qwt_plot_zoneitem.h \
|
||||||
|
$$PWD/qwt_plot_zoomer.h \
|
||||||
|
$$PWD/qwt_point_3d.h \
|
||||||
|
$$PWD/qwt_point_data.h \
|
||||||
|
$$PWD/qwt_point_mapper.h \
|
||||||
|
$$PWD/qwt_point_polar.h \
|
||||||
|
$$PWD/qwt_raster_data.h \
|
||||||
|
$$PWD/qwt_round_scale_draw.h \
|
||||||
|
$$PWD/qwt_samples.h \
|
||||||
|
$$PWD/qwt_sampling_thread.h \
|
||||||
|
$$PWD/qwt_scale_div.h \
|
||||||
|
$$PWD/qwt_scale_draw.h \
|
||||||
|
$$PWD/qwt_scale_engine.h \
|
||||||
|
$$PWD/qwt_scale_map.h \
|
||||||
|
$$PWD/qwt_scale_widget.h \
|
||||||
|
$$PWD/qwt_series_data.h \
|
||||||
|
$$PWD/qwt_series_store.h \
|
||||||
|
$$PWD/qwt_slider.h \
|
||||||
|
$$PWD/qwt_spline.h \
|
||||||
|
$$PWD/qwt_symbol.h \
|
||||||
|
$$PWD/qwt_system_clock.h \
|
||||||
|
$$PWD/qwt_text.h \
|
||||||
|
$$PWD/qwt_text_engine.h \
|
||||||
|
$$PWD/qwt_text_label.h \
|
||||||
|
$$PWD/qwt_thermo.h \
|
||||||
|
$$PWD/qwt_transform.h \
|
||||||
|
$$PWD/qwt_wheel.h \
|
||||||
|
$$PWD/qwt_widget_overlay.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/qwt_abstract_legend.cpp \
|
||||||
|
$$PWD/qwt_abstract_scale.cpp \
|
||||||
|
$$PWD/qwt_abstract_scale_draw.cpp \
|
||||||
|
$$PWD/qwt_abstract_slider.cpp \
|
||||||
|
$$PWD/qwt_analog_clock.cpp \
|
||||||
|
$$PWD/qwt_arrow_button.cpp \
|
||||||
|
$$PWD/qwt_clipper.cpp \
|
||||||
|
$$PWD/qwt_color_map.cpp \
|
||||||
|
$$PWD/qwt_column_symbol.cpp \
|
||||||
|
$$PWD/qwt_compass.cpp \
|
||||||
|
$$PWD/qwt_compass_rose.cpp \
|
||||||
|
$$PWD/qwt_counter.cpp \
|
||||||
|
$$PWD/qwt_curve_fitter.cpp \
|
||||||
|
$$PWD/qwt_date.cpp \
|
||||||
|
$$PWD/qwt_date_scale_draw.cpp \
|
||||||
|
$$PWD/qwt_date_scale_engine.cpp \
|
||||||
|
$$PWD/qwt_dial.cpp \
|
||||||
|
$$PWD/qwt_dial_needle.cpp \
|
||||||
|
$$PWD/qwt_dyngrid_layout.cpp \
|
||||||
|
$$PWD/qwt_event_pattern.cpp \
|
||||||
|
$$PWD/qwt_graphic.cpp \
|
||||||
|
$$PWD/qwt_interval.cpp \
|
||||||
|
$$PWD/qwt_interval_symbol.cpp \
|
||||||
|
$$PWD/qwt_knob.cpp \
|
||||||
|
$$PWD/qwt_legend.cpp \
|
||||||
|
$$PWD/qwt_legend_data.cpp \
|
||||||
|
$$PWD/qwt_legend_label.cpp \
|
||||||
|
$$PWD/qwt_magnifier.cpp \
|
||||||
|
$$PWD/qwt_math.cpp \
|
||||||
|
$$PWD/qwt_matrix_raster_data.cpp \
|
||||||
|
$$PWD/qwt_null_paintdevice.cpp \
|
||||||
|
$$PWD/qwt_painter.cpp \
|
||||||
|
$$PWD/qwt_painter_command.cpp \
|
||||||
|
$$PWD/qwt_panner.cpp \
|
||||||
|
$$PWD/qwt_picker.cpp \
|
||||||
|
$$PWD/qwt_picker_machine.cpp \
|
||||||
|
$$PWD/qwt_pixel_matrix.cpp \
|
||||||
|
$$PWD/qwt_plot.cpp \
|
||||||
|
$$PWD/qwt_plot_abstract_barchart.cpp \
|
||||||
|
$$PWD/qwt_plot_axis.cpp \
|
||||||
|
$$PWD/qwt_plot_barchart.cpp \
|
||||||
|
$$PWD/qwt_plot_canvas.cpp \
|
||||||
|
$$PWD/qwt_plot_curve.cpp \
|
||||||
|
$$PWD/qwt_plot_dict.cpp \
|
||||||
|
$$PWD/qwt_plot_directpainter.cpp \
|
||||||
|
$$PWD/qwt_plot_grid.cpp \
|
||||||
|
$$PWD/qwt_plot_histogram.cpp \
|
||||||
|
$$PWD/qwt_plot_intervalcurve.cpp \
|
||||||
|
$$PWD/qwt_plot_item.cpp \
|
||||||
|
$$PWD/qwt_plot_layout.cpp \
|
||||||
|
$$PWD/qwt_plot_legenditem.cpp \
|
||||||
|
$$PWD/qwt_plot_magnifier.cpp \
|
||||||
|
$$PWD/qwt_plot_marker.cpp \
|
||||||
|
$$PWD/qwt_plot_multi_barchart.cpp \
|
||||||
|
$$PWD/qwt_plot_panner.cpp \
|
||||||
|
$$PWD/qwt_plot_picker.cpp \
|
||||||
|
$$PWD/qwt_plot_rasteritem.cpp \
|
||||||
|
$$PWD/qwt_plot_renderer.cpp \
|
||||||
|
$$PWD/qwt_plot_rescaler.cpp \
|
||||||
|
$$PWD/qwt_plot_scaleitem.cpp \
|
||||||
|
$$PWD/qwt_plot_seriesitem.cpp \
|
||||||
|
$$PWD/qwt_plot_shapeitem.cpp \
|
||||||
|
$$PWD/qwt_plot_spectrocurve.cpp \
|
||||||
|
$$PWD/qwt_plot_spectrogram.cpp \
|
||||||
|
$$PWD/qwt_plot_textlabel.cpp \
|
||||||
|
$$PWD/qwt_plot_tradingcurve.cpp \
|
||||||
|
$$PWD/qwt_plot_xml.cpp \
|
||||||
|
$$PWD/qwt_plot_zoneitem.cpp \
|
||||||
|
$$PWD/qwt_plot_zoomer.cpp \
|
||||||
|
$$PWD/qwt_point_3d.cpp \
|
||||||
|
$$PWD/qwt_point_data.cpp \
|
||||||
|
$$PWD/qwt_point_mapper.cpp \
|
||||||
|
$$PWD/qwt_point_polar.cpp \
|
||||||
|
$$PWD/qwt_raster_data.cpp \
|
||||||
|
$$PWD/qwt_round_scale_draw.cpp \
|
||||||
|
$$PWD/qwt_sampling_thread.cpp \
|
||||||
|
$$PWD/qwt_scale_div.cpp \
|
||||||
|
$$PWD/qwt_scale_draw.cpp \
|
||||||
|
$$PWD/qwt_scale_engine.cpp \
|
||||||
|
$$PWD/qwt_scale_map.cpp \
|
||||||
|
$$PWD/qwt_scale_widget.cpp \
|
||||||
|
$$PWD/qwt_series_data.cpp \
|
||||||
|
$$PWD/qwt_slider.cpp \
|
||||||
|
$$PWD/qwt_spline.cpp \
|
||||||
|
$$PWD/qwt_symbol.cpp \
|
||||||
|
$$PWD/qwt_system_clock.cpp \
|
||||||
|
$$PWD/qwt_text.cpp \
|
||||||
|
$$PWD/qwt_text_engine.cpp \
|
||||||
|
$$PWD/qwt_text_label.cpp \
|
||||||
|
$$PWD/qwt_thermo.cpp \
|
||||||
|
$$PWD/qwt_transform.cpp \
|
||||||
|
$$PWD/qwt_wheel.cpp \
|
||||||
|
$$PWD/qwt_widget_overlay.cpp
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_H
|
||||||
|
#define QWT_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Some constants for use within Qwt.
|
||||||
|
*/
|
||||||
|
namespace Qwt
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- 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 "qwt_abstract_legend.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtAbstractLegend::QwtAbstractLegend( QWidget *parent ):
|
||||||
|
QFrame( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAbstractLegend::~QwtAbstractLegend()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return the extent, that is needed for elements to scroll
|
||||||
|
the legend ( usually scrollbars ),
|
||||||
|
|
||||||
|
\param orientation Orientation
|
||||||
|
\return Extent of the corresponding scroll element
|
||||||
|
*/
|
||||||
|
int QwtAbstractLegend::scrollExtent( Qt::Orientation orientation ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( orientation );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ABSTRACT_LEGEND_H
|
||||||
|
#define QWT_ABSTRACT_LEGEND_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_legend_data.h"
|
||||||
|
#include <qframe.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
|
||||||
|
class QVariant;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Abstract base class for legend widgets
|
||||||
|
|
||||||
|
Legends, that need to be under control of the QwtPlot layout system
|
||||||
|
need to be derived from QwtAbstractLegend.
|
||||||
|
|
||||||
|
\note Other type of legends can be implemented by connecting to
|
||||||
|
the QwtPlot::legendDataChanged() signal. But as these legends
|
||||||
|
are unknown to the plot layout system the layout code
|
||||||
|
( on screen and for QwtPlotRenderer ) need to be organized
|
||||||
|
in application code.
|
||||||
|
|
||||||
|
\sa QwtLegend
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtAbstractLegend : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QwtAbstractLegend( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtAbstractLegend();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Render the legend into a given rectangle.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param rect Bounding rectangle
|
||||||
|
\param fillBackground When true, fill rect with the widget background
|
||||||
|
|
||||||
|
\sa renderLegend() is used by QwtPlotRenderer
|
||||||
|
*/
|
||||||
|
virtual void renderLegend( QPainter *painter,
|
||||||
|
const QRectF &rect, bool fillBackground ) const = 0;
|
||||||
|
|
||||||
|
//! \return True, when no plot item is inserted
|
||||||
|
virtual bool isEmpty() const = 0;
|
||||||
|
|
||||||
|
virtual int scrollExtent( Qt::Orientation ) const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Update the entries for a plot item
|
||||||
|
|
||||||
|
\param itemInfo Info about an item
|
||||||
|
\param data List of legend entry attributes for the item
|
||||||
|
*/
|
||||||
|
virtual void updateLegend( const QVariant &itemInfo,
|
||||||
|
const QList<QwtLegendData> &data ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,449 @@
|
|||||||
|
/* -*- 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 "qwt_abstract_scale.h"
|
||||||
|
#include "qwt_scale_engine.h"
|
||||||
|
#include "qwt_scale_draw.h"
|
||||||
|
#include "qwt_scale_div.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
|
||||||
|
class QwtAbstractScale::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
maxMajor( 5 ),
|
||||||
|
maxMinor( 3 ),
|
||||||
|
stepSize( 0.0 )
|
||||||
|
{
|
||||||
|
scaleEngine = new QwtLinearScaleEngine();
|
||||||
|
scaleDraw = new QwtScaleDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
~PrivateData()
|
||||||
|
{
|
||||||
|
delete scaleEngine;
|
||||||
|
delete scaleDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtScaleEngine *scaleEngine;
|
||||||
|
QwtAbstractScaleDraw *scaleDraw;
|
||||||
|
|
||||||
|
int maxMajor;
|
||||||
|
int maxMinor;
|
||||||
|
double stepSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\param parent Parent widget
|
||||||
|
|
||||||
|
Creates a default QwtScaleDraw and a QwtLinearScaleEngine.
|
||||||
|
The initial scale boundaries are set to [ 0.0, 100.0 ]
|
||||||
|
|
||||||
|
The scaleStepSize() is initialized to 0.0, scaleMaxMajor() to 5
|
||||||
|
and scaleMaxMajor to 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QwtAbstractScale::QwtAbstractScale( QWidget *parent ):
|
||||||
|
QWidget( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
rescale( 0.0, 100.0, d_data->stepSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAbstractScale::~QwtAbstractScale()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the lower bound of the scale
|
||||||
|
|
||||||
|
\param value Lower bound
|
||||||
|
|
||||||
|
\sa lowerBound(), setScale(), setUpperBound()
|
||||||
|
\note For inverted scales the lower bound
|
||||||
|
is greater than the upper bound
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setLowerBound( double value )
|
||||||
|
{
|
||||||
|
setScale( value, upperBound() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Lower bound of the scale
|
||||||
|
\sa setLowerBound(), setScale(), upperBound()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::lowerBound() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleDiv().lowerBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the upper bound of the scale
|
||||||
|
|
||||||
|
\param value Upper bound
|
||||||
|
|
||||||
|
\sa upperBound(), setScale(), setLowerBound()
|
||||||
|
\note For inverted scales the lower bound
|
||||||
|
is greater than the upper bound
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setUpperBound( double value )
|
||||||
|
{
|
||||||
|
setScale( lowerBound(), value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Upper bound of the scale
|
||||||
|
\sa setUpperBound(), setScale(), lowerBound()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::upperBound() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleDiv().upperBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Specify a scale.
|
||||||
|
|
||||||
|
Define a scale by an interval
|
||||||
|
|
||||||
|
The ticks are calculated using scaleMaxMinor(),
|
||||||
|
scaleMaxMajor() and scaleStepSize().
|
||||||
|
|
||||||
|
\param lowerBound lower limit of the scale interval
|
||||||
|
\param upperBound upper limit of the scale interval
|
||||||
|
|
||||||
|
\note For inverted scales the lower bound
|
||||||
|
is greater than the upper bound
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScale( double lowerBound, double upperBound )
|
||||||
|
{
|
||||||
|
rescale( lowerBound, upperBound, d_data->stepSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Specify a scale.
|
||||||
|
|
||||||
|
Define a scale by an interval
|
||||||
|
|
||||||
|
The ticks are calculated using scaleMaxMinor(),
|
||||||
|
scaleMaxMajor() and scaleStepSize().
|
||||||
|
|
||||||
|
\param interval Interval
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScale( const QwtInterval &interval )
|
||||||
|
{
|
||||||
|
setScale( interval.minValue(), interval.maxValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Specify a scale.
|
||||||
|
|
||||||
|
scaleMaxMinor(), scaleMaxMajor() and scaleStepSize() and have no effect.
|
||||||
|
|
||||||
|
\param scaleDiv Scale division
|
||||||
|
\sa setAutoScale()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScale( const QwtScaleDiv &scaleDiv )
|
||||||
|
{
|
||||||
|
if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
if ( d_data->scaleEngine )
|
||||||
|
{
|
||||||
|
d_data->scaleDraw->setTransformation(
|
||||||
|
d_data->scaleEngine->transformation() );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
d_data->scaleDraw->setScaleDiv( scaleDiv );
|
||||||
|
|
||||||
|
scaleChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the maximum number of major tick intervals.
|
||||||
|
|
||||||
|
The scale's major ticks are calculated automatically such that
|
||||||
|
the number of major intervals does not exceed ticks.
|
||||||
|
|
||||||
|
The default value is 5.
|
||||||
|
|
||||||
|
\param ticks Maximal number of major ticks.
|
||||||
|
|
||||||
|
\sa scaleMaxMajor(), setScaleMaxMinor(),
|
||||||
|
setScaleStepSize(), QwtScaleEngine::divideInterval()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScaleMaxMajor( int ticks )
|
||||||
|
{
|
||||||
|
if ( ticks != d_data->maxMajor )
|
||||||
|
{
|
||||||
|
d_data->maxMajor = ticks;
|
||||||
|
updateScaleDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Maximal number of major tick intervals
|
||||||
|
\sa setScaleMaxMajor(), scaleMaxMinor()
|
||||||
|
*/
|
||||||
|
int QwtAbstractScale::scaleMaxMajor() const
|
||||||
|
{
|
||||||
|
return d_data->maxMajor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the maximum number of minor tick intervals
|
||||||
|
|
||||||
|
The scale's minor ticks are calculated automatically such that
|
||||||
|
the number of minor intervals does not exceed ticks.
|
||||||
|
The default value is 3.
|
||||||
|
|
||||||
|
\param ticks Maximal number of minor ticks.
|
||||||
|
|
||||||
|
\sa scaleMaxMajor(), setScaleMaxMinor(),
|
||||||
|
setScaleStepSize(), QwtScaleEngine::divideInterval()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScaleMaxMinor( int ticks )
|
||||||
|
{
|
||||||
|
if ( ticks != d_data->maxMinor )
|
||||||
|
{
|
||||||
|
d_data->maxMinor = ticks;
|
||||||
|
updateScaleDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Maximal number of minor tick intervals
|
||||||
|
\sa setScaleMaxMinor(), scaleMaxMajor()
|
||||||
|
*/
|
||||||
|
int QwtAbstractScale::scaleMaxMinor() const
|
||||||
|
{
|
||||||
|
return d_data->maxMinor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the step size used for calculating a scale division
|
||||||
|
|
||||||
|
The step size is hint for calculating the intervals for
|
||||||
|
the major ticks of the scale. A value of 0.0 is interpreted
|
||||||
|
as no hint.
|
||||||
|
|
||||||
|
\param stepSize Hint for the step size of the scale
|
||||||
|
|
||||||
|
\sa scaleStepSize(), QwtScaleEngine::divideScale()
|
||||||
|
|
||||||
|
\note Position and distance between the major ticks also
|
||||||
|
depends on scaleMaxMajor().
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScaleStepSize( double stepSize )
|
||||||
|
{
|
||||||
|
if ( stepSize != d_data->stepSize )
|
||||||
|
{
|
||||||
|
d_data->stepSize = stepSize;
|
||||||
|
updateScaleDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Hint for the step size of the scale
|
||||||
|
\sa setScaleStepSize(), QwtScaleEngine::divideScale()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::scaleStepSize() const
|
||||||
|
{
|
||||||
|
return d_data->stepSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set a scale draw
|
||||||
|
|
||||||
|
scaleDraw has to be created with new and will be deleted in
|
||||||
|
the destructor or the next call of setAbstractScaleDraw().
|
||||||
|
|
||||||
|
\sa abstractScaleDraw()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setAbstractScaleDraw( QwtAbstractScaleDraw *scaleDraw )
|
||||||
|
{
|
||||||
|
if ( scaleDraw == NULL || scaleDraw == d_data->scaleDraw )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( d_data->scaleDraw != NULL )
|
||||||
|
scaleDraw->setScaleDiv( d_data->scaleDraw->scaleDiv() );
|
||||||
|
|
||||||
|
delete d_data->scaleDraw;
|
||||||
|
d_data->scaleDraw = scaleDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale draw
|
||||||
|
\sa setAbstractScaleDraw()
|
||||||
|
*/
|
||||||
|
QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw()
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale draw
|
||||||
|
\sa setAbstractScaleDraw()
|
||||||
|
*/
|
||||||
|
const QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set a scale engine
|
||||||
|
|
||||||
|
The scale engine is responsible for calculating the scale division
|
||||||
|
and provides a transformation between scale and widget coordinates.
|
||||||
|
|
||||||
|
scaleEngine has to be created with new and will be deleted in
|
||||||
|
the destructor or the next call of setScaleEngine.
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::setScaleEngine( QwtScaleEngine *scaleEngine )
|
||||||
|
{
|
||||||
|
if ( scaleEngine != NULL && scaleEngine != d_data->scaleEngine )
|
||||||
|
{
|
||||||
|
delete d_data->scaleEngine;
|
||||||
|
d_data->scaleEngine = scaleEngine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale engine
|
||||||
|
\sa setScaleEngine()
|
||||||
|
*/
|
||||||
|
const QwtScaleEngine *QwtAbstractScale::scaleEngine() const
|
||||||
|
{
|
||||||
|
return d_data->scaleEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale engine
|
||||||
|
\sa setScaleEngine()
|
||||||
|
*/
|
||||||
|
QwtScaleEngine *QwtAbstractScale::scaleEngine()
|
||||||
|
{
|
||||||
|
return d_data->scaleEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale boundaries and positions of the ticks
|
||||||
|
|
||||||
|
The scale division might have been assigned explicitly
|
||||||
|
or calculated implicitly by rescale().
|
||||||
|
*/
|
||||||
|
const QwtScaleDiv &QwtAbstractScale::scaleDiv() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleDiv();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Map to translate between scale and widget coordinates
|
||||||
|
*/
|
||||||
|
const QwtScaleMap &QwtAbstractScale::scaleMap() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate a scale value into a widget coordinate
|
||||||
|
|
||||||
|
\param value Scale value
|
||||||
|
\return Corresponding widget coordinate for value
|
||||||
|
\sa scaleMap(), invTransform()
|
||||||
|
*/
|
||||||
|
int QwtAbstractScale::transform( double value ) const
|
||||||
|
{
|
||||||
|
return qRound( d_data->scaleDraw->scaleMap().transform( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate a widget coordinate into a scale value
|
||||||
|
|
||||||
|
\param value Widget coordinate
|
||||||
|
\return Corresponding scale coordinate for value
|
||||||
|
\sa scaleMap(), transform()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::invTransform( int value ) const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleMap().invTransform( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when the scale is increasing in opposite direction
|
||||||
|
to the widget coordinates
|
||||||
|
*/
|
||||||
|
bool QwtAbstractScale::isInverted() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDraw->scaleMap().isInverting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The boundary with the smaller value
|
||||||
|
\sa maximum(), lowerBound(), upperBound()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::minimum() const
|
||||||
|
{
|
||||||
|
return qMin( d_data->scaleDraw->scaleDiv().lowerBound(),
|
||||||
|
d_data->scaleDraw->scaleDiv().upperBound() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The boundary with the larger value
|
||||||
|
\sa minimum(), lowerBound(), upperBound()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScale::maximum() const
|
||||||
|
{
|
||||||
|
return qMax( d_data->scaleDraw->scaleDiv().lowerBound(),
|
||||||
|
d_data->scaleDraw->scaleDiv().upperBound() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Notify changed scale
|
||||||
|
void QwtAbstractScale::scaleChange()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Recalculate the scale division and update the scale.
|
||||||
|
|
||||||
|
\param lowerBound Lower limit of the scale interval
|
||||||
|
\param upperBound Upper limit of the scale interval
|
||||||
|
\param stepSize Major step size
|
||||||
|
|
||||||
|
\sa scaleChange()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScale::rescale(
|
||||||
|
double lowerBound, double upperBound, double stepSize )
|
||||||
|
{
|
||||||
|
const QwtScaleDiv scaleDiv = d_data->scaleEngine->divideScale(
|
||||||
|
lowerBound, upperBound, d_data->maxMajor, d_data->maxMinor, stepSize );
|
||||||
|
|
||||||
|
if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
d_data->scaleDraw->setTransformation(
|
||||||
|
d_data->scaleEngine->transformation() );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
d_data->scaleDraw->setScaleDiv( scaleDiv );
|
||||||
|
scaleChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtAbstractScale::updateScaleDraw()
|
||||||
|
{
|
||||||
|
rescale( d_data->scaleDraw->scaleDiv().lowerBound(),
|
||||||
|
d_data->scaleDraw->scaleDiv().upperBound(), d_data->stepSize );
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ABSTRACT_SCALE_H
|
||||||
|
#define QWT_ABSTRACT_SCALE_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qwidget.h>
|
||||||
|
|
||||||
|
class QwtScaleEngine;
|
||||||
|
class QwtAbstractScaleDraw;
|
||||||
|
class QwtScaleDiv;
|
||||||
|
class QwtScaleMap;
|
||||||
|
class QwtInterval;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief An abstract base class for widgets having a scale
|
||||||
|
|
||||||
|
The scale of an QwtAbstractScale is determined by a QwtScaleDiv
|
||||||
|
definition, that contains the boundaries and the ticks of the scale.
|
||||||
|
The scale is painted using a QwtScaleDraw object.
|
||||||
|
|
||||||
|
The scale division might be assigned explicitly - but usually
|
||||||
|
it is calculated from the boundaries using a QwtScaleEngine.
|
||||||
|
|
||||||
|
The scale engine also decides the type of transformation of the scale
|
||||||
|
( linear, logarithmic ... ).
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtAbstractScale: public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( double lowerBound READ lowerBound WRITE setLowerBound )
|
||||||
|
Q_PROPERTY( double upperBound READ upperBound WRITE setUpperBound )
|
||||||
|
|
||||||
|
Q_PROPERTY( int scaleMaxMajor READ scaleMaxMajor WRITE setScaleMaxMajor )
|
||||||
|
Q_PROPERTY( int scaleMaxMinor READ scaleMaxMinor WRITE setScaleMaxMinor )
|
||||||
|
|
||||||
|
Q_PROPERTY( double scaleStepSize READ scaleStepSize WRITE setScaleStepSize )
|
||||||
|
|
||||||
|
public:
|
||||||
|
QwtAbstractScale( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtAbstractScale();
|
||||||
|
|
||||||
|
void setScale( double lowerBound, double upperBound );
|
||||||
|
void setScale( const QwtInterval & );
|
||||||
|
void setScale( const QwtScaleDiv & );
|
||||||
|
|
||||||
|
const QwtScaleDiv& scaleDiv() const;
|
||||||
|
|
||||||
|
void setLowerBound( double value );
|
||||||
|
double lowerBound() const;
|
||||||
|
|
||||||
|
void setUpperBound( double value );
|
||||||
|
double upperBound() const;
|
||||||
|
|
||||||
|
void setScaleStepSize( double stepSize );
|
||||||
|
double scaleStepSize() const;
|
||||||
|
|
||||||
|
void setScaleMaxMajor( int ticks );
|
||||||
|
int scaleMaxMinor() const;
|
||||||
|
|
||||||
|
void setScaleMaxMinor( int ticks );
|
||||||
|
int scaleMaxMajor() const;
|
||||||
|
|
||||||
|
void setScaleEngine( QwtScaleEngine * );
|
||||||
|
const QwtScaleEngine *scaleEngine() const;
|
||||||
|
QwtScaleEngine *scaleEngine();
|
||||||
|
|
||||||
|
int transform( double ) const;
|
||||||
|
double invTransform( int ) const;
|
||||||
|
|
||||||
|
bool isInverted() const;
|
||||||
|
|
||||||
|
double minimum() const;
|
||||||
|
double maximum() const;
|
||||||
|
|
||||||
|
const QwtScaleMap &scaleMap() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void rescale( double lowerBound,
|
||||||
|
double upperBound, double stepSize );
|
||||||
|
|
||||||
|
void setAbstractScaleDraw( QwtAbstractScaleDraw * );
|
||||||
|
|
||||||
|
const QwtAbstractScaleDraw *abstractScaleDraw() const;
|
||||||
|
QwtAbstractScaleDraw *abstractScaleDraw();
|
||||||
|
|
||||||
|
virtual void scaleChange();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateScaleDraw();
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,419 @@
|
|||||||
|
/* -*- 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 "qwt_abstract_scale_draw.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
#include <qlocale.h>
|
||||||
|
|
||||||
|
class QwtAbstractScaleDraw::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
spacing( 4.0 ),
|
||||||
|
penWidth( 0 ),
|
||||||
|
minExtent( 0.0 )
|
||||||
|
{
|
||||||
|
components = QwtAbstractScaleDraw::Backbone
|
||||||
|
| QwtAbstractScaleDraw::Ticks
|
||||||
|
| QwtAbstractScaleDraw::Labels;
|
||||||
|
|
||||||
|
tickLength[QwtScaleDiv::MinorTick] = 4.0;
|
||||||
|
tickLength[QwtScaleDiv::MediumTick] = 6.0;
|
||||||
|
tickLength[QwtScaleDiv::MajorTick] = 8.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScaleComponents components;
|
||||||
|
|
||||||
|
QwtScaleMap map;
|
||||||
|
QwtScaleDiv scaleDiv;
|
||||||
|
|
||||||
|
double spacing;
|
||||||
|
double tickLength[QwtScaleDiv::NTickTypes];
|
||||||
|
int penWidth;
|
||||||
|
|
||||||
|
double 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAbstractScaleDraw::~QwtAbstractScaleDraw()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
En/Disable a component of the scale
|
||||||
|
|
||||||
|
\param component Scale component
|
||||||
|
\param enable On/Off
|
||||||
|
|
||||||
|
\sa hasComponent()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::enableComponent(
|
||||||
|
ScaleComponent component, bool enable )
|
||||||
|
{
|
||||||
|
if ( enable )
|
||||||
|
d_data->components |= component;
|
||||||
|
else
|
||||||
|
d_data->components &= ~component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Check if a component is enabled
|
||||||
|
|
||||||
|
\param component Component type
|
||||||
|
\return true, when component is enabled
|
||||||
|
\sa enableComponent()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const
|
||||||
|
{
|
||||||
|
return ( d_data->components & component );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the scale division
|
||||||
|
\param scaleDiv New scale division
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &scaleDiv )
|
||||||
|
{
|
||||||
|
d_data->scaleDiv = scaleDiv;
|
||||||
|
d_data->map.setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() );
|
||||||
|
d_data->labelCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the transformation of the scale
|
||||||
|
\param transformation New scale transformation
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::setTransformation(
|
||||||
|
QwtTransform *transformation )
|
||||||
|
{
|
||||||
|
d_data->map.setTransformation( transformation );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Map how to translate between scale and pixel values
|
||||||
|
const QwtScaleMap &QwtAbstractScaleDraw::scaleMap() const
|
||||||
|
{
|
||||||
|
return d_data->map;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Map how to translate between scale and pixel values
|
||||||
|
QwtScaleMap &QwtAbstractScaleDraw::scaleMap()
|
||||||
|
{
|
||||||
|
return d_data->map;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return scale division
|
||||||
|
const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const
|
||||||
|
{
|
||||||
|
return d_data->scaleDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Specify the width of the scale pen
|
||||||
|
\param width Pen width
|
||||||
|
\sa penWidth()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::setPenWidth( int width )
|
||||||
|
{
|
||||||
|
if ( width < 0 )
|
||||||
|
width = 0;
|
||||||
|
|
||||||
|
if ( width != d_data->penWidth )
|
||||||
|
d_data->penWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Scale pen width
|
||||||
|
\sa setPenWidth()
|
||||||
|
*/
|
||||||
|
int QwtAbstractScaleDraw::penWidth() const
|
||||||
|
{
|
||||||
|
return d_data->penWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the scale
|
||||||
|
|
||||||
|
\param painter The painter
|
||||||
|
|
||||||
|
\param palette Palette, text color is used for the labels,
|
||||||
|
foreground color for ticks and backbone
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::draw( QPainter *painter,
|
||||||
|
const QPalette& palette ) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QPen pen = painter->pen();
|
||||||
|
pen.setWidth( d_data->penWidth );
|
||||||
|
pen.setCosmetic( false );
|
||||||
|
painter->setPen( pen );
|
||||||
|
|
||||||
|
if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style
|
||||||
|
|
||||||
|
const QList<double> &majorTicks =
|
||||||
|
d_data->scaleDiv.ticks( QwtScaleDiv::MajorTick );
|
||||||
|
|
||||||
|
for ( int i = 0; i < majorTicks.count(); i++ )
|
||||||
|
{
|
||||||
|
const double v = majorTicks[i];
|
||||||
|
if ( d_data->scaleDiv.contains( v ) )
|
||||||
|
drawLabel( painter, v );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
pen = painter->pen();
|
||||||
|
pen.setColor( palette.color( QPalette::WindowText ) );
|
||||||
|
pen.setCapStyle( Qt::FlatCap );
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
|
||||||
|
for ( int tickType = QwtScaleDiv::MinorTick;
|
||||||
|
tickType < QwtScaleDiv::NTickTypes; tickType++ )
|
||||||
|
{
|
||||||
|
const double tickLen = d_data->tickLength[tickType];
|
||||||
|
if ( tickLen <= 0.0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QList<double> &ticks = d_data->scaleDiv.ticks( tickType );
|
||||||
|
for ( int i = 0; i < ticks.count(); i++ )
|
||||||
|
{
|
||||||
|
const double v = ticks[i];
|
||||||
|
if ( d_data->scaleDiv.contains( v ) )
|
||||||
|
drawTick( painter, v, tickLen );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
pen = painter->pen();
|
||||||
|
pen.setColor( palette.color( QPalette::WindowText ) );
|
||||||
|
pen.setCapStyle( Qt::FlatCap );
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
|
||||||
|
drawBackbone( painter );
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 spacing()
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::setSpacing( double 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.
|
||||||
|
|
||||||
|
\return Spacing
|
||||||
|
\sa setSpacing()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScaleDraw::spacing() const
|
||||||
|
{
|
||||||
|
return d_data->spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set a minimum for the extent
|
||||||
|
|
||||||
|
The extent is calculated from the components 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( double minExtent )
|
||||||
|
{
|
||||||
|
if ( minExtent < 0.0 )
|
||||||
|
minExtent = 0.0;
|
||||||
|
|
||||||
|
d_data->minExtent = minExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Get the minimum extent
|
||||||
|
\return Minimum extent
|
||||||
|
\sa extent(), setMinimumExtent()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScaleDraw::minimumExtent() const
|
||||||
|
{
|
||||||
|
return d_data->minExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the length of the ticks
|
||||||
|
|
||||||
|
\param tickType Tick type
|
||||||
|
\param length New length
|
||||||
|
|
||||||
|
\warning the length is limited to [0..1000]
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::setTickLength(
|
||||||
|
QwtScaleDiv::TickType tickType, double length )
|
||||||
|
{
|
||||||
|
if ( tickType < QwtScaleDiv::MinorTick ||
|
||||||
|
tickType > QwtScaleDiv::MajorTick )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( length < 0.0 )
|
||||||
|
length = 0.0;
|
||||||
|
|
||||||
|
const double maxTickLen = 1000.0;
|
||||||
|
if ( length > maxTickLen )
|
||||||
|
length = maxTickLen;
|
||||||
|
|
||||||
|
d_data->tickLength[tickType] = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Length of the ticks
|
||||||
|
\sa setTickLength(), maxTickLength()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScaleDraw::tickLength( QwtScaleDiv::TickType tickType ) const
|
||||||
|
{
|
||||||
|
if ( tickType < QwtScaleDiv::MinorTick ||
|
||||||
|
tickType > QwtScaleDiv::MajorTick )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d_data->tickLength[tickType];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Length of the longest tick
|
||||||
|
|
||||||
|
Useful for layout calculations
|
||||||
|
\sa tickLength(), setTickLength()
|
||||||
|
*/
|
||||||
|
double QwtAbstractScaleDraw::maxTickLength() const
|
||||||
|
{
|
||||||
|
double length = 0.0;
|
||||||
|
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
|
||||||
|
length = qMax( length, d_data->tickLength[i] );
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Convert a value into its representing label
|
||||||
|
|
||||||
|
The value is converted to a plain text using
|
||||||
|
QLocale().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().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
|
||||||
|
for rich text in Qt4), so it's necessary to cache the labels.
|
||||||
|
|
||||||
|
\param font Font
|
||||||
|
\param value Value
|
||||||
|
|
||||||
|
\return Tick label
|
||||||
|
*/
|
||||||
|
const QwtText &QwtAbstractScaleDraw::tickLabel(
|
||||||
|
const QFont &font, double value ) const
|
||||||
|
{
|
||||||
|
QMap<double, QwtText>::const_iterator it1 = d_data->labelCache.constFind( value );
|
||||||
|
if ( it1 != d_data->labelCache.constEnd() )
|
||||||
|
return *it1;
|
||||||
|
|
||||||
|
QwtText lbl = label( value );
|
||||||
|
lbl.setRenderFlags( 0 );
|
||||||
|
lbl.setLayoutAttribute( QwtText::MinimumLayout );
|
||||||
|
|
||||||
|
( void )lbl.textSize( font ); // initialize the internal cache
|
||||||
|
|
||||||
|
QMap<double, QwtText>::iterator it2 = d_data->labelCache.insert( value, lbl );
|
||||||
|
return *it2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invalidate the cache used by tickLabel()
|
||||||
|
|
||||||
|
The cache is invalidated, when a new QwtScaleDiv is set. If
|
||||||
|
the labels need to be changed. while the same QwtScaleDiv is set,
|
||||||
|
invalidateCache() needs to be called manually.
|
||||||
|
*/
|
||||||
|
void QwtAbstractScaleDraw::invalidateCache()
|
||||||
|
{
|
||||||
|
d_data->labelCache.clear();
|
||||||
|
}
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ABSTRACT_SCALE_DRAW_H
|
||||||
|
#define QWT_ABSTRACT_SCALE_DRAW_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_scale_div.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
|
|
||||||
|
class QPalette;
|
||||||
|
class QPainter;
|
||||||
|
class QFont;
|
||||||
|
class QwtTransform;
|
||||||
|
class QwtScaleMap;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A abstract base class for drawing scales
|
||||||
|
|
||||||
|
QwtAbstractScaleDraw can be used to draw linear or logarithmic scales.
|
||||||
|
|
||||||
|
After a scale division has been specified as a QwtScaleDiv object
|
||||||
|
using setScaleDiv(), the scale can be drawn with the draw() member.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtAbstractScaleDraw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Components of a scale
|
||||||
|
\sa enableComponent(), hasComponent
|
||||||
|
*/
|
||||||
|
enum ScaleComponent
|
||||||
|
{
|
||||||
|
//! Backbone = the line where the ticks are located
|
||||||
|
Backbone = 0x01,
|
||||||
|
|
||||||
|
//! Ticks
|
||||||
|
Ticks = 0x02,
|
||||||
|
|
||||||
|
//! Labels
|
||||||
|
Labels = 0x04
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Scale components
|
||||||
|
typedef QFlags<ScaleComponent> ScaleComponents;
|
||||||
|
|
||||||
|
QwtAbstractScaleDraw();
|
||||||
|
virtual ~QwtAbstractScaleDraw();
|
||||||
|
|
||||||
|
void setScaleDiv( const QwtScaleDiv & );
|
||||||
|
const QwtScaleDiv& scaleDiv() const;
|
||||||
|
|
||||||
|
void setTransformation( QwtTransform * );
|
||||||
|
const QwtScaleMap &scaleMap() const;
|
||||||
|
QwtScaleMap &scaleMap();
|
||||||
|
|
||||||
|
void enableComponent( ScaleComponent, bool enable = true );
|
||||||
|
bool hasComponent( ScaleComponent ) const;
|
||||||
|
|
||||||
|
void setTickLength( QwtScaleDiv::TickType, double length );
|
||||||
|
double tickLength( QwtScaleDiv::TickType ) const;
|
||||||
|
double maxTickLength() const;
|
||||||
|
|
||||||
|
void setSpacing( double );
|
||||||
|
double spacing() const;
|
||||||
|
|
||||||
|
void setPenWidth( int width );
|
||||||
|
int penWidth() const;
|
||||||
|
|
||||||
|
virtual void draw( QPainter *, const QPalette & ) const;
|
||||||
|
|
||||||
|
virtual QwtText label( double ) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the extent
|
||||||
|
|
||||||
|
The extent is the distance from the baseline to the outermost
|
||||||
|
pixel of the scale draw in opposite to its orientation.
|
||||||
|
It is at least minimumExtent() pixels.
|
||||||
|
|
||||||
|
\param font Font used for drawing the tick labels
|
||||||
|
\return Number of pixels
|
||||||
|
|
||||||
|
\sa setMinimumExtent(), minimumExtent()
|
||||||
|
*/
|
||||||
|
virtual double extent( const QFont &font ) const = 0;
|
||||||
|
|
||||||
|
void setMinimumExtent( double );
|
||||||
|
double minimumExtent() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
Draw a tick
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param value Value of the tick
|
||||||
|
\param len Length of the tick
|
||||||
|
|
||||||
|
\sa drawBackbone(), drawLabel()
|
||||||
|
*/
|
||||||
|
virtual void drawTick( QPainter *painter, double value, double len ) const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws the baseline of the scale
|
||||||
|
\param painter Painter
|
||||||
|
|
||||||
|
\sa drawTick(), drawLabel()
|
||||||
|
*/
|
||||||
|
virtual void drawBackbone( QPainter *painter ) const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws the label for a major scale tick
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param value Value
|
||||||
|
|
||||||
|
\sa drawTick(), drawBackbone()
|
||||||
|
*/
|
||||||
|
virtual void drawLabel( QPainter *painter, double value ) const = 0;
|
||||||
|
|
||||||
|
void invalidateCache();
|
||||||
|
const QwtText &tickLabel( const QFont &, double value ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QwtAbstractScaleDraw( const QwtAbstractScaleDraw & );
|
||||||
|
QwtAbstractScaleDraw &operator=( const QwtAbstractScaleDraw & );
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtAbstractScaleDraw::ScaleComponents )
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,822 @@
|
|||||||
|
/* -*- 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 "qwt_abstract_slider.h"
|
||||||
|
#include "qwt_abstract_scale_draw.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040601
|
||||||
|
#define qFabs(x) ::fabs(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static double qwtAlignToScaleDiv(
|
||||||
|
const QwtAbstractSlider *slider, double value )
|
||||||
|
{
|
||||||
|
const QwtScaleDiv &sd = slider->scaleDiv();
|
||||||
|
|
||||||
|
const int tValue = slider->transform( value );
|
||||||
|
|
||||||
|
if ( tValue == slider->transform( sd.lowerBound() ) )
|
||||||
|
return sd.lowerBound();
|
||||||
|
|
||||||
|
if ( tValue == slider->transform( sd.upperBound() ) )
|
||||||
|
return sd.upperBound();
|
||||||
|
|
||||||
|
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
|
||||||
|
{
|
||||||
|
const QList<double> ticks = sd.ticks( i );
|
||||||
|
for ( int j = 0; j < ticks.size(); j++ )
|
||||||
|
{
|
||||||
|
if ( slider->transform( ticks[ j ] ) == tValue )
|
||||||
|
return ticks[ j ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtAbstractSlider::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
isScrolling( false ),
|
||||||
|
isTracking( true ),
|
||||||
|
pendingValueChanged( false ),
|
||||||
|
readOnly( false ),
|
||||||
|
totalSteps( 100 ),
|
||||||
|
singleSteps( 1 ),
|
||||||
|
pageSteps( 10 ),
|
||||||
|
stepAlignment( true ),
|
||||||
|
isValid( false ),
|
||||||
|
value( 0.0 ),
|
||||||
|
wrapping( false ),
|
||||||
|
invertedControls( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isScrolling;
|
||||||
|
bool isTracking;
|
||||||
|
bool pendingValueChanged;
|
||||||
|
|
||||||
|
bool readOnly;
|
||||||
|
|
||||||
|
uint totalSteps;
|
||||||
|
uint singleSteps;
|
||||||
|
uint pageSteps;
|
||||||
|
bool stepAlignment;
|
||||||
|
|
||||||
|
bool isValid;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
bool wrapping;
|
||||||
|
bool invertedControls;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
|
||||||
|
The scale is initialized to [0.0, 100.0], the
|
||||||
|
number of steps is set to 100 with 1 and 10 and single
|
||||||
|
an page step sizes. Step alignment is enabled.
|
||||||
|
|
||||||
|
The initial value is invalid.
|
||||||
|
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
|
||||||
|
QwtAbstractScale( parent )
|
||||||
|
{
|
||||||
|
d_data = new QwtAbstractSlider::PrivateData;
|
||||||
|
|
||||||
|
setScale( 0.0, 100.0 );
|
||||||
|
setFocusPolicy( Qt::StrongFocus );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAbstractSlider::~QwtAbstractSlider()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the value to be valid/invalid
|
||||||
|
|
||||||
|
\param on When true, the value is invalidated
|
||||||
|
|
||||||
|
\sa setValue()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setValid( bool on )
|
||||||
|
{
|
||||||
|
if ( on != d_data->isValid )
|
||||||
|
{
|
||||||
|
d_data->isValid = on;
|
||||||
|
sliderChange();
|
||||||
|
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return True, when the value is invalid
|
||||||
|
bool QwtAbstractSlider::isValid() const
|
||||||
|
{
|
||||||
|
return d_data->isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
En/Disable read only mode
|
||||||
|
|
||||||
|
In read only mode the slider can't be controlled by mouse
|
||||||
|
or keyboard.
|
||||||
|
|
||||||
|
\param on Enables in case of true
|
||||||
|
\sa isReadOnly()
|
||||||
|
|
||||||
|
\warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setReadOnly( bool on )
|
||||||
|
{
|
||||||
|
if ( d_data->readOnly != on )
|
||||||
|
{
|
||||||
|
d_data->readOnly = on;
|
||||||
|
setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
In read only mode the slider can't be controlled by mouse
|
||||||
|
or keyboard.
|
||||||
|
|
||||||
|
\return true if read only
|
||||||
|
\sa setReadOnly()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractSlider::isReadOnly() const
|
||||||
|
{
|
||||||
|
return d_data->readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Enables or disables tracking.
|
||||||
|
|
||||||
|
If tracking is enabled, the slider emits the valueChanged()
|
||||||
|
signal while the movable part of the slider is being dragged.
|
||||||
|
If tracking is disabled, the slider emits the valueChanged() signal
|
||||||
|
only when the user releases the slider.
|
||||||
|
|
||||||
|
Tracking is enabled by default.
|
||||||
|
\param on \c true (enable) or \c false (disable) tracking.
|
||||||
|
|
||||||
|
\sa isTracking(), sliderMoved()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setTracking( bool on )
|
||||||
|
{
|
||||||
|
d_data->isTracking = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when tracking has been enabled
|
||||||
|
\sa setTracking()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractSlider::isTracking() const
|
||||||
|
{
|
||||||
|
return d_data->isTracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Mouse press event handler
|
||||||
|
\param event Mouse event
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !d_data->isValid || lowerBound() == upperBound() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data->isScrolling = isScrollPosition( event->pos() );
|
||||||
|
|
||||||
|
if ( d_data->isScrolling )
|
||||||
|
{
|
||||||
|
d_data->pendingValueChanged = false;
|
||||||
|
|
||||||
|
Q_EMIT sliderPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Mouse Move Event handler
|
||||||
|
\param event Mouse event
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->isValid && d_data->isScrolling )
|
||||||
|
{
|
||||||
|
double value = scrolledTo( event->pos() );
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
value = boundedValue( value );
|
||||||
|
|
||||||
|
if ( d_data->stepAlignment )
|
||||||
|
{
|
||||||
|
value = alignedValue( value );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = qwtAlignToScaleDiv( this, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
|
||||||
|
sliderChange();
|
||||||
|
|
||||||
|
Q_EMIT sliderMoved( d_data->value );
|
||||||
|
|
||||||
|
if ( d_data->isTracking )
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
else
|
||||||
|
d_data->pendingValueChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Mouse Release Event handler
|
||||||
|
\param event Mouse event
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->isScrolling && d_data->isValid )
|
||||||
|
{
|
||||||
|
d_data->isScrolling = false;
|
||||||
|
|
||||||
|
if ( d_data->pendingValueChanged )
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
|
||||||
|
Q_EMIT sliderReleased();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Wheel Event handler
|
||||||
|
|
||||||
|
In/decreases the value by s number of steps. The direction
|
||||||
|
depends on the invertedControls() property.
|
||||||
|
|
||||||
|
When the control or shift modifier is pressed the wheel delta
|
||||||
|
( divided by 120 ) is mapped to an increment according to
|
||||||
|
pageSteps(). Otherwise it is mapped to singleSteps().
|
||||||
|
|
||||||
|
\param event Wheel event
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !d_data->isValid || d_data->isScrolling )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int numSteps = 0;
|
||||||
|
|
||||||
|
if ( ( event->modifiers() & Qt::ControlModifier) ||
|
||||||
|
( event->modifiers() & Qt::ShiftModifier ) )
|
||||||
|
{
|
||||||
|
// one page regardless of delta
|
||||||
|
numSteps = d_data->pageSteps;
|
||||||
|
if ( event->delta() < 0 )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int numTurns = ( event->delta() / 120 );
|
||||||
|
numSteps = numTurns * d_data->singleSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->invertedControls )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
|
||||||
|
const double value = incrementedValue( d_data->value, numSteps );
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
sliderChange();
|
||||||
|
|
||||||
|
Q_EMIT sliderMoved( d_data->value );
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handles key events
|
||||||
|
|
||||||
|
QwtAbstractSlider handles the following keys:
|
||||||
|
|
||||||
|
- Qt::Key_Left\n
|
||||||
|
Add/Subtract singleSteps() in direction to lowerBound();
|
||||||
|
- Qt::Key_Right\n
|
||||||
|
Add/Subtract singleSteps() in direction to upperBound();
|
||||||
|
- Qt::Key_Down\n
|
||||||
|
Subtract singleSteps(), when invertedControls() is false
|
||||||
|
- Qt::Key_Up\n
|
||||||
|
Add singleSteps(), when invertedControls() is false
|
||||||
|
- Qt::Key_PageDown\n
|
||||||
|
Subtract pageSteps(), when invertedControls() is false
|
||||||
|
- Qt::Key_PageUp\n
|
||||||
|
Add pageSteps(), when invertedControls() is false
|
||||||
|
- Qt::Key_Home\n
|
||||||
|
Set the value to the minimum()
|
||||||
|
- Qt::Key_End\n
|
||||||
|
Set the value to the maximum()
|
||||||
|
|
||||||
|
\param event Key event
|
||||||
|
\sa isReadOnly()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !d_data->isValid || d_data->isScrolling )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int numSteps = 0;
|
||||||
|
double value = d_data->value;
|
||||||
|
|
||||||
|
switch ( event->key() )
|
||||||
|
{
|
||||||
|
case Qt::Key_Left:
|
||||||
|
{
|
||||||
|
numSteps = -static_cast<int>( d_data->singleSteps );
|
||||||
|
if ( isInverted() )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Right:
|
||||||
|
{
|
||||||
|
numSteps = d_data->singleSteps;
|
||||||
|
if ( isInverted() )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Down:
|
||||||
|
{
|
||||||
|
numSteps = -static_cast<int>( d_data->singleSteps );
|
||||||
|
if ( d_data->invertedControls )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Up:
|
||||||
|
{
|
||||||
|
numSteps = d_data->singleSteps;
|
||||||
|
if ( d_data->invertedControls )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_PageUp:
|
||||||
|
{
|
||||||
|
numSteps = d_data->pageSteps;
|
||||||
|
if ( d_data->invertedControls )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_PageDown:
|
||||||
|
{
|
||||||
|
numSteps = -static_cast<int>( d_data->pageSteps );
|
||||||
|
if ( d_data->invertedControls )
|
||||||
|
numSteps = -numSteps;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Home:
|
||||||
|
{
|
||||||
|
value = minimum();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_End:
|
||||||
|
{
|
||||||
|
value = maximum();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( numSteps != 0 )
|
||||||
|
{
|
||||||
|
value = incrementedValue( d_data->value, numSteps );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
sliderChange();
|
||||||
|
|
||||||
|
Q_EMIT sliderMoved( d_data->value );
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the number of steps
|
||||||
|
|
||||||
|
The range of the slider is divided into a number of steps from
|
||||||
|
which the value increments according to user inputs depend.
|
||||||
|
|
||||||
|
The default setting is 100.
|
||||||
|
|
||||||
|
\param stepCount Number of steps
|
||||||
|
|
||||||
|
\sa totalSteps(), setSingleSteps(), setPageSteps()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setTotalSteps( uint stepCount )
|
||||||
|
{
|
||||||
|
d_data->totalSteps = stepCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of steps
|
||||||
|
\sa setTotalSteps(), singleSteps(), pageSteps()
|
||||||
|
*/
|
||||||
|
uint QwtAbstractSlider::totalSteps() const
|
||||||
|
{
|
||||||
|
return d_data->totalSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the number of steps for a single increment
|
||||||
|
|
||||||
|
The range of the slider is divided into a number of steps from
|
||||||
|
which the value increments according to user inputs depend.
|
||||||
|
|
||||||
|
\param stepCount Number of steps
|
||||||
|
|
||||||
|
\sa singleSteps(), setTotalSteps(), setPageSteps()
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QwtAbstractSlider::setSingleSteps( uint stepCount )
|
||||||
|
{
|
||||||
|
d_data->singleSteps = stepCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of steps
|
||||||
|
\sa setSingleSteps(), totalSteps(), pageSteps()
|
||||||
|
*/
|
||||||
|
uint QwtAbstractSlider::singleSteps() const
|
||||||
|
{
|
||||||
|
return d_data->singleSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the number of steps for a page increment
|
||||||
|
|
||||||
|
The range of the slider is divided into a number of steps from
|
||||||
|
which the value increments according to user inputs depend.
|
||||||
|
|
||||||
|
\param stepCount Number of steps
|
||||||
|
|
||||||
|
\sa pageSteps(), setTotalSteps(), setSingleSteps()
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QwtAbstractSlider::setPageSteps( uint stepCount )
|
||||||
|
{
|
||||||
|
d_data->pageSteps = stepCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of steps
|
||||||
|
\sa setPageSteps(), totalSteps(), singleSteps()
|
||||||
|
*/
|
||||||
|
uint QwtAbstractSlider::pageSteps() const
|
||||||
|
{
|
||||||
|
return d_data->pageSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Enable step alignment
|
||||||
|
|
||||||
|
When step alignment is enabled values resulting from slider
|
||||||
|
movements are aligned to the step size.
|
||||||
|
|
||||||
|
\param on Enable step alignment when true
|
||||||
|
\sa stepAlignment()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setStepAlignment( bool on )
|
||||||
|
{
|
||||||
|
if ( on != d_data->stepAlignment )
|
||||||
|
{
|
||||||
|
d_data->stepAlignment = on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when step alignment is enabled
|
||||||
|
\sa setStepAlignment()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractSlider::stepAlignment() const
|
||||||
|
{
|
||||||
|
return d_data->stepAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the slider to the specified value
|
||||||
|
|
||||||
|
\param value New value
|
||||||
|
\sa setValid(), sliderChange(), valueChanged()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setValue( double value )
|
||||||
|
{
|
||||||
|
value = qBound( minimum(), value, maximum() );
|
||||||
|
|
||||||
|
const bool changed = ( d_data->value != value ) || !d_data->isValid;
|
||||||
|
|
||||||
|
d_data->value = value;
|
||||||
|
d_data->isValid = true;
|
||||||
|
|
||||||
|
if ( changed )
|
||||||
|
{
|
||||||
|
sliderChange();
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns the current value.
|
||||||
|
double QwtAbstractSlider::value() const
|
||||||
|
{
|
||||||
|
return d_data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
If wrapping is true stepping up from upperBound() value will
|
||||||
|
take you to the minimum() value and vice versa.
|
||||||
|
|
||||||
|
\param on En/Disable wrapping
|
||||||
|
\sa wrapping()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setWrapping( bool on )
|
||||||
|
{
|
||||||
|
d_data->wrapping = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when wrapping is set
|
||||||
|
\sa setWrapping()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractSlider::wrapping() const
|
||||||
|
{
|
||||||
|
return d_data->wrapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invert wheel and key events
|
||||||
|
|
||||||
|
Usually scrolling the mouse wheel "up" and using keys like page
|
||||||
|
up will increase the slider's value towards its maximum.
|
||||||
|
When invertedControls() is enabled the value is scrolled
|
||||||
|
towards its minimum.
|
||||||
|
|
||||||
|
Inverting the controls might be f.e. useful for a vertical slider
|
||||||
|
with an inverted scale ( decreasing from top to bottom ).
|
||||||
|
|
||||||
|
\param on Invert controls, when true
|
||||||
|
|
||||||
|
\sa invertedControls(), keyEvent(), wheelEvent()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::setInvertedControls( bool on )
|
||||||
|
{
|
||||||
|
d_data->invertedControls = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when the controls are inverted
|
||||||
|
\sa setInvertedControls()
|
||||||
|
*/
|
||||||
|
bool QwtAbstractSlider::invertedControls() const
|
||||||
|
{
|
||||||
|
return d_data->invertedControls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Increment the slider
|
||||||
|
|
||||||
|
The step size depends on the number of totalSteps()
|
||||||
|
|
||||||
|
\param stepCount Number of steps
|
||||||
|
\sa setTotalSteps(), incrementedValue()
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::incrementValue( int stepCount )
|
||||||
|
{
|
||||||
|
const double value = incrementedValue(
|
||||||
|
d_data->value, stepCount );
|
||||||
|
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
sliderChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Increment a value
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\param stepCount Number of steps
|
||||||
|
|
||||||
|
\return Incremented value
|
||||||
|
*/
|
||||||
|
double QwtAbstractSlider::incrementedValue(
|
||||||
|
double value, int stepCount ) const
|
||||||
|
{
|
||||||
|
if ( d_data->totalSteps == 0 )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
const QwtTransform *transformation =
|
||||||
|
scaleMap().transformation();
|
||||||
|
|
||||||
|
if ( transformation == NULL )
|
||||||
|
{
|
||||||
|
const double range = maximum() - minimum();
|
||||||
|
value += stepCount * range / d_data->totalSteps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QwtScaleMap map = scaleMap();
|
||||||
|
map.setPaintInterval( 0, d_data->totalSteps );
|
||||||
|
|
||||||
|
// we need equidant steps according to
|
||||||
|
// paint device coordinates
|
||||||
|
const double range = transformation->transform( maximum() )
|
||||||
|
- transformation->transform( minimum() );
|
||||||
|
|
||||||
|
const double stepSize = range / d_data->totalSteps;
|
||||||
|
|
||||||
|
double v = transformation->transform( value );
|
||||||
|
|
||||||
|
v = qRound( v / stepSize ) * stepSize;
|
||||||
|
v += stepCount * range / d_data->totalSteps;
|
||||||
|
|
||||||
|
value = transformation->invTransform( v );
|
||||||
|
}
|
||||||
|
|
||||||
|
value = boundedValue( value );
|
||||||
|
|
||||||
|
if ( d_data->stepAlignment )
|
||||||
|
value = alignedValue( value );
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double QwtAbstractSlider::boundedValue( double value ) const
|
||||||
|
{
|
||||||
|
const double vmin = minimum();
|
||||||
|
const double vmax = maximum();
|
||||||
|
|
||||||
|
if ( d_data->wrapping && vmin != vmax )
|
||||||
|
{
|
||||||
|
const int fullCircle = 360 * 16;
|
||||||
|
|
||||||
|
const double pd = scaleMap().pDist();
|
||||||
|
if ( int( pd / fullCircle ) * fullCircle == pd )
|
||||||
|
{
|
||||||
|
// full circle scales: min and max are the same
|
||||||
|
const double range = vmax - vmin;
|
||||||
|
|
||||||
|
if ( value < vmin )
|
||||||
|
{
|
||||||
|
value += ::ceil( ( vmin - value ) / range ) * range;
|
||||||
|
}
|
||||||
|
else if ( value > vmax )
|
||||||
|
{
|
||||||
|
value -= ::ceil( ( value - vmax ) / range ) * range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( value < vmin )
|
||||||
|
value = vmax;
|
||||||
|
else if ( value > vmax )
|
||||||
|
value = vmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = qBound( vmin, value, vmax );
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double QwtAbstractSlider::alignedValue( double value ) const
|
||||||
|
{
|
||||||
|
if ( d_data->totalSteps == 0 )
|
||||||
|
return value;
|
||||||
|
|
||||||
|
double stepSize;
|
||||||
|
|
||||||
|
if ( scaleMap().transformation() == NULL )
|
||||||
|
{
|
||||||
|
stepSize = ( maximum() - minimum() ) / d_data->totalSteps;
|
||||||
|
if ( stepSize > 0.0 )
|
||||||
|
{
|
||||||
|
value = lowerBound() +
|
||||||
|
qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps;
|
||||||
|
|
||||||
|
if ( stepSize > 0.0 )
|
||||||
|
{
|
||||||
|
double v = scaleMap().transform( value );
|
||||||
|
|
||||||
|
v = scaleMap().p1() +
|
||||||
|
qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
|
||||||
|
|
||||||
|
value = scaleMap().invTransform( v );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( qAbs( stepSize ) > 1e-12 )
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
|
||||||
|
{
|
||||||
|
// correct rounding error if value = 0
|
||||||
|
value = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// correct rounding error at the border
|
||||||
|
if ( qFuzzyCompare( value, upperBound() ) )
|
||||||
|
value = upperBound();
|
||||||
|
else if ( qFuzzyCompare( value, lowerBound() ) )
|
||||||
|
value = lowerBound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Update the slider according to modifications of the scale
|
||||||
|
*/
|
||||||
|
void QwtAbstractSlider::scaleChange()
|
||||||
|
{
|
||||||
|
const double value = qBound( minimum(), d_data->value, maximum() );
|
||||||
|
|
||||||
|
const bool changed = ( value != d_data->value );
|
||||||
|
if ( changed )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->isValid || changed )
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Calling update()
|
||||||
|
void QwtAbstractSlider::sliderChange()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
@ -0,0 +1,167 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ABSTRACT_SLIDER_H
|
||||||
|
#define QWT_ABSTRACT_SLIDER_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_abstract_scale.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief An abstract base class for slider widgets with a scale
|
||||||
|
|
||||||
|
A slider widget displays a value according to a scale.
|
||||||
|
The class is designed as a common super class for widgets like
|
||||||
|
QwtKnob, QwtDial and QwtSlider.
|
||||||
|
|
||||||
|
When the slider is nor readOnly() its value can be modified
|
||||||
|
by keyboard, mouse and wheel inputs.
|
||||||
|
|
||||||
|
The range of the slider is divided into a number of steps from
|
||||||
|
which the value increments according to user inputs depend.
|
||||||
|
Only for linear scales the number of steps correspond with
|
||||||
|
a fixed step size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtAbstractSlider: public QwtAbstractScale
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( double value READ value WRITE setValue )
|
||||||
|
|
||||||
|
Q_PROPERTY( uint totalSteps READ totalSteps WRITE setTotalSteps )
|
||||||
|
Q_PROPERTY( uint singleSteps READ singleSteps WRITE setSingleSteps )
|
||||||
|
Q_PROPERTY( uint pageSteps READ pageSteps WRITE setPageSteps )
|
||||||
|
Q_PROPERTY( bool stepAlignment READ stepAlignment WRITE setStepAlignment )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
|
||||||
|
Q_PROPERTY( bool tracking READ isTracking WRITE setTracking )
|
||||||
|
Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool invertedControls READ invertedControls WRITE setInvertedControls )
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QwtAbstractSlider( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtAbstractSlider();
|
||||||
|
|
||||||
|
void setValid( bool );
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
double value() const;
|
||||||
|
|
||||||
|
void setWrapping( bool );
|
||||||
|
bool wrapping() const;
|
||||||
|
|
||||||
|
void setTotalSteps( uint );
|
||||||
|
uint totalSteps() const;
|
||||||
|
|
||||||
|
void setSingleSteps( uint );
|
||||||
|
uint singleSteps() const;
|
||||||
|
|
||||||
|
void setPageSteps( uint );
|
||||||
|
uint pageSteps() const;
|
||||||
|
|
||||||
|
void setStepAlignment( bool );
|
||||||
|
bool stepAlignment() const;
|
||||||
|
|
||||||
|
void setTracking( bool );
|
||||||
|
bool isTracking() const;
|
||||||
|
|
||||||
|
void setReadOnly( bool );
|
||||||
|
bool isReadOnly() const;
|
||||||
|
|
||||||
|
void setInvertedControls( bool );
|
||||||
|
bool invertedControls() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setValue( double value );
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Notify a change of value.
|
||||||
|
|
||||||
|
When tracking is enabled (default setting),
|
||||||
|
this signal will be emitted every time the value changes.
|
||||||
|
|
||||||
|
\param value New value
|
||||||
|
|
||||||
|
\sa setTracking(), sliderMoved()
|
||||||
|
*/
|
||||||
|
void valueChanged( double value );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This signal is emitted when the user presses the
|
||||||
|
movable part of the slider.
|
||||||
|
*/
|
||||||
|
void sliderPressed();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This signal is emitted when the user releases the
|
||||||
|
movable part of the slider.
|
||||||
|
*/
|
||||||
|
void sliderReleased();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This signal is emitted when the user moves the
|
||||||
|
slider with the mouse.
|
||||||
|
|
||||||
|
\param value New value
|
||||||
|
|
||||||
|
\sa valueChanged()
|
||||||
|
*/
|
||||||
|
void sliderMoved( double value );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void mousePressEvent( QMouseEvent * );
|
||||||
|
virtual void mouseReleaseEvent( QMouseEvent * );
|
||||||
|
virtual void mouseMoveEvent( QMouseEvent * );
|
||||||
|
virtual void keyPressEvent( QKeyEvent * );
|
||||||
|
virtual void wheelEvent( QWheelEvent * );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine what to do when the user presses a mouse button.
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\retval True, when pos is a valid scroll position
|
||||||
|
\sa scrolledTo()
|
||||||
|
*/
|
||||||
|
virtual bool isScrollPosition( const QPoint &pos ) const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine the value for a new position of the
|
||||||
|
movable part of the slider
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\return Value for the mouse position
|
||||||
|
\sa isScrollPosition()
|
||||||
|
*/
|
||||||
|
virtual double scrolledTo( const QPoint &pos ) const = 0;
|
||||||
|
|
||||||
|
void incrementValue( int stepCount );
|
||||||
|
|
||||||
|
virtual void scaleChange();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void sliderChange();
|
||||||
|
|
||||||
|
double incrementedValue(
|
||||||
|
double value, int stepCount ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double alignedValue( double ) const;
|
||||||
|
double boundedValue( double ) const;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,244 @@
|
|||||||
|
/* -*- 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 "qwt_analog_clock.h"
|
||||||
|
#include "qwt_round_scale_draw.h"
|
||||||
|
#include <qmath.h>
|
||||||
|
#include <qlocale.h>
|
||||||
|
|
||||||
|
class QwtAnalogClockScaleDraw: public QwtRoundScaleDraw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtAnalogClockScaleDraw()
|
||||||
|
{
|
||||||
|
setSpacing( 8 );
|
||||||
|
|
||||||
|
enableComponent( QwtAbstractScaleDraw::Backbone, false );
|
||||||
|
|
||||||
|
setTickLength( QwtScaleDiv::MinorTick, 2 );
|
||||||
|
setTickLength( QwtScaleDiv::MediumTick, 4 );
|
||||||
|
setTickLength( QwtScaleDiv::MajorTick, 8 );
|
||||||
|
|
||||||
|
setPenWidth( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QwtText label( double value ) const
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
|
||||||
|
value = 60.0 * 60.0 * 12.0;
|
||||||
|
|
||||||
|
return QLocale().toString( qRound( value / ( 60.0 * 60.0 ) ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtAnalogClock::QwtAnalogClock( QWidget *parent ):
|
||||||
|
QwtDial( parent )
|
||||||
|
{
|
||||||
|
setWrapping( true );
|
||||||
|
setReadOnly( true );
|
||||||
|
|
||||||
|
setOrigin( 270.0 );
|
||||||
|
setScaleDraw( new QwtAnalogClockScaleDraw() );
|
||||||
|
|
||||||
|
setTotalSteps( 60 );
|
||||||
|
|
||||||
|
const int secondsPerHour = 60.0 * 60.0;
|
||||||
|
|
||||||
|
QList<double> majorTicks;
|
||||||
|
QList<double> minorTicks;
|
||||||
|
|
||||||
|
for ( int i = 0; i < 12; i++ )
|
||||||
|
{
|
||||||
|
majorTicks += i * secondsPerHour;
|
||||||
|
|
||||||
|
for ( int j = 1; j < 5; j++ )
|
||||||
|
minorTicks += i * secondsPerHour + j * secondsPerHour / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtScaleDiv scaleDiv;
|
||||||
|
scaleDiv.setInterval( 0.0, 12.0 * secondsPerHour );
|
||||||
|
scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks );
|
||||||
|
scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks );
|
||||||
|
setScale( scaleDiv );
|
||||||
|
|
||||||
|
QColor knobColor = palette().color( QPalette::Active, QPalette::Text );
|
||||||
|
knobColor = knobColor.dark( 120 );
|
||||||
|
|
||||||
|
QColor handColor;
|
||||||
|
int width;
|
||||||
|
|
||||||
|
for ( int i = 0; i < NHands; i++ )
|
||||||
|
{
|
||||||
|
if ( i == SecondHand )
|
||||||
|
{
|
||||||
|
width = 2;
|
||||||
|
handColor = knobColor.dark( 120 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
width = 8;
|
||||||
|
handColor = knobColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtDialSimpleNeedle *hand = new QwtDialSimpleNeedle(
|
||||||
|
QwtDialSimpleNeedle::Arrow, true, handColor, knobColor );
|
||||||
|
hand->setWidth( width );
|
||||||
|
|
||||||
|
d_hand[i] = NULL;
|
||||||
|
setHand( static_cast<Hand>( i ), hand );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAnalogClock::~QwtAnalogClock()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < NHands; i++ )
|
||||||
|
delete d_hand[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Nop method, use setHand() instead
|
||||||
|
\sa setHand()
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::setNeedle( QwtDialNeedle * )
|
||||||
|
{
|
||||||
|
// no op
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set a clock hand
|
||||||
|
\param hand Specifies the type of hand
|
||||||
|
\param needle Hand
|
||||||
|
\sa hand()
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::setHand( Hand hand, QwtDialNeedle *needle )
|
||||||
|
{
|
||||||
|
if ( hand >= 0 && hand < NHands )
|
||||||
|
{
|
||||||
|
delete d_hand[hand];
|
||||||
|
d_hand[hand] = needle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Clock hand
|
||||||
|
\param hd Specifies the type of hand
|
||||||
|
\sa setHand()
|
||||||
|
*/
|
||||||
|
QwtDialNeedle *QwtAnalogClock::hand( Hand hd )
|
||||||
|
{
|
||||||
|
if ( hd < 0 || hd >= NHands )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return d_hand[hd];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Clock hand
|
||||||
|
\param hd Specifies the type of hand
|
||||||
|
\sa setHand()
|
||||||
|
*/
|
||||||
|
const QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) const
|
||||||
|
{
|
||||||
|
return const_cast<QwtAnalogClock *>( this )->hand( hd );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the current time
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::setCurrentTime()
|
||||||
|
{
|
||||||
|
setTime( QTime::currentTime() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set a time
|
||||||
|
\param time Time to display
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::setTime( const QTime &time )
|
||||||
|
{
|
||||||
|
if ( time.isValid() )
|
||||||
|
{
|
||||||
|
setValue( ( time.hour() % 12 ) * 60.0 * 60.0
|
||||||
|
+ time.minute() * 60.0 + time.second() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setValid( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the needle
|
||||||
|
|
||||||
|
A clock has no single needle but three hands instead. drawNeedle()
|
||||||
|
translates value() into directions for the hands and calls
|
||||||
|
drawHand().
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the clock
|
||||||
|
\param radius Maximum length for the hands
|
||||||
|
\param dir Dummy, not used.
|
||||||
|
\param colorGroup ColorGroup
|
||||||
|
|
||||||
|
\sa drawHand()
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::drawNeedle( QPainter *painter, const QPointF ¢er,
|
||||||
|
double radius, double dir, QPalette::ColorGroup colorGroup ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( dir );
|
||||||
|
|
||||||
|
if ( isValid() )
|
||||||
|
{
|
||||||
|
const double hours = value() / ( 60.0 * 60.0 );
|
||||||
|
const double minutes =
|
||||||
|
( value() - qFloor(hours) * 60.0 * 60.0 ) / 60.0;
|
||||||
|
const double seconds = value() - qFloor(hours) * 60.0 * 60.0
|
||||||
|
- qFloor(minutes) * 60.0;
|
||||||
|
|
||||||
|
double angle[NHands];
|
||||||
|
angle[HourHand] = 360.0 * hours / 12.0;
|
||||||
|
angle[MinuteHand] = 360.0 * minutes / 60.0;
|
||||||
|
angle[SecondHand] = 360.0 * seconds / 60.0;
|
||||||
|
|
||||||
|
for ( int hand = 0; hand < NHands; hand++ )
|
||||||
|
{
|
||||||
|
const double d = 360.0 - angle[hand] - origin();
|
||||||
|
drawHand( painter, static_cast<Hand>( hand ),
|
||||||
|
center, radius, d, colorGroup );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw a clock hand
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param hd Specify the type of hand
|
||||||
|
\param center Center of the clock
|
||||||
|
\param radius Maximum length for the hands
|
||||||
|
\param direction Direction of the hand in degrees, counter clockwise
|
||||||
|
\param cg ColorGroup
|
||||||
|
*/
|
||||||
|
void QwtAnalogClock::drawHand( QPainter *painter, Hand hd,
|
||||||
|
const QPointF ¢er, double radius, double direction,
|
||||||
|
QPalette::ColorGroup cg ) const
|
||||||
|
{
|
||||||
|
const QwtDialNeedle *needle = hand( hd );
|
||||||
|
if ( needle )
|
||||||
|
{
|
||||||
|
if ( hd == HourHand )
|
||||||
|
radius = qRound( 0.8 * radius );
|
||||||
|
|
||||||
|
needle->draw( painter, center, radius, direction, cg );
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ANALOG_CLOCK_H
|
||||||
|
#define QWT_ANALOG_CLOCK_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_dial.h"
|
||||||
|
#include "qwt_dial_needle.h"
|
||||||
|
#include <qdatetime.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief An analog clock
|
||||||
|
|
||||||
|
\image html analogclock.png
|
||||||
|
|
||||||
|
\par Example
|
||||||
|
\code
|
||||||
|
#include <qwt_analog_clock.h>
|
||||||
|
|
||||||
|
QwtAnalogClock *clock = new QwtAnalogClock(...);
|
||||||
|
clock->scaleDraw()->setPenWidth(3);
|
||||||
|
clock->setLineWidth(6);
|
||||||
|
clock->setFrameShadow(QwtDial::Sunken);
|
||||||
|
clock->setTime();
|
||||||
|
|
||||||
|
// update the clock every second
|
||||||
|
QTimer *timer = new QTimer(clock);
|
||||||
|
timer->connect(timer, SIGNAL(timeout()), clock, SLOT(setCurrentTime()));
|
||||||
|
timer->start(1000);
|
||||||
|
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note The examples/dials example shows how to use QwtAnalogClock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtAnalogClock: public QwtDial
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Hand type
|
||||||
|
\sa setHand(), hand()
|
||||||
|
*/
|
||||||
|
enum Hand
|
||||||
|
{
|
||||||
|
//! Needle displaying the seconds
|
||||||
|
SecondHand,
|
||||||
|
|
||||||
|
//! Needle displaying the minutes
|
||||||
|
MinuteHand,
|
||||||
|
|
||||||
|
//! Needle displaying the hours
|
||||||
|
HourHand,
|
||||||
|
|
||||||
|
//! Number of needles
|
||||||
|
NHands
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit QwtAnalogClock( QWidget* parent = NULL );
|
||||||
|
virtual ~QwtAnalogClock();
|
||||||
|
|
||||||
|
void setHand( Hand, QwtDialNeedle * );
|
||||||
|
|
||||||
|
const QwtDialNeedle *hand( Hand ) const;
|
||||||
|
QwtDialNeedle *hand( Hand );
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setCurrentTime();
|
||||||
|
void setTime( const QTime & );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawNeedle( QPainter *, const QPointF &,
|
||||||
|
double radius, double direction, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
virtual void drawHand( QPainter *, Hand, const QPointF &,
|
||||||
|
double radius, double direction, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// use setHand instead
|
||||||
|
void setNeedle( QwtDialNeedle * );
|
||||||
|
|
||||||
|
QwtDialNeedle *d_hand[NHands];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,333 @@
|
|||||||
|
/* -*- 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 "qwt_arrow_button.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
#include <qstyleoption.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qapplication.h>
|
||||||
|
|
||||||
|
static const int MaxNum = 3;
|
||||||
|
static const int Margin = 2;
|
||||||
|
static const int Spacing = 1;
|
||||||
|
|
||||||
|
class QwtArrowButton::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int num;
|
||||||
|
Qt::ArrowType arrowType;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QStyleOptionButton styleOpt( const QwtArrowButton* btn )
|
||||||
|
{
|
||||||
|
QStyleOptionButton option;
|
||||||
|
option.init( btn );
|
||||||
|
option.features = QStyleOptionButton::None;
|
||||||
|
if ( btn->isFlat() )
|
||||||
|
option.features |= QStyleOptionButton::Flat;
|
||||||
|
if ( btn->menu() )
|
||||||
|
option.features |= QStyleOptionButton::HasMenu;
|
||||||
|
if ( btn->autoDefault() || btn->isDefault() )
|
||||||
|
option.features |= QStyleOptionButton::AutoDefaultButton;
|
||||||
|
if ( btn->isDefault() )
|
||||||
|
option.features |= QStyleOptionButton::DefaultButton;
|
||||||
|
if ( btn->isDown() )
|
||||||
|
option.state |= QStyle::State_Sunken;
|
||||||
|
if ( !btn->isFlat() && !btn->isDown() )
|
||||||
|
option.state |= QStyle::State_Raised;
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param num Number of arrows
|
||||||
|
\param arrowType see Qt::ArrowType in the Qt docs.
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtArrowButton::QwtArrowButton( int num,
|
||||||
|
Qt::ArrowType arrowType, QWidget *parent ):
|
||||||
|
QPushButton( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
d_data->num = qBound( 1, num, MaxNum );
|
||||||
|
d_data->arrowType = arrowType;
|
||||||
|
|
||||||
|
setAutoRepeat( true );
|
||||||
|
setAutoDefault( false );
|
||||||
|
|
||||||
|
switch ( d_data->arrowType )
|
||||||
|
{
|
||||||
|
case Qt::LeftArrow:
|
||||||
|
case Qt::RightArrow:
|
||||||
|
setSizePolicy( QSizePolicy::Expanding,
|
||||||
|
QSizePolicy::Fixed );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setSizePolicy( QSizePolicy::Fixed,
|
||||||
|
QSizePolicy::Expanding );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtArrowButton::~QwtArrowButton()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
d_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The direction of the arrows
|
||||||
|
*/
|
||||||
|
Qt::ArrowType QwtArrowButton::arrowType() const
|
||||||
|
{
|
||||||
|
return d_data->arrowType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The number of arrows
|
||||||
|
*/
|
||||||
|
int QwtArrowButton::num() const
|
||||||
|
{
|
||||||
|
return d_data->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the bounding rectangle for the label
|
||||||
|
*/
|
||||||
|
QRect QwtArrowButton::labelRect() const
|
||||||
|
{
|
||||||
|
const int m = Margin;
|
||||||
|
|
||||||
|
QRect r = rect();
|
||||||
|
r.setRect( r.x() + m, r.y() + m,
|
||||||
|
r.width() - 2 * m, r.height() - 2 * m );
|
||||||
|
|
||||||
|
if ( isDown() )
|
||||||
|
{
|
||||||
|
QStyleOptionButton option = styleOpt( this );
|
||||||
|
const int ph = style()->pixelMetric(
|
||||||
|
QStyle::PM_ButtonShiftHorizontal, &option, this );
|
||||||
|
const int pv = style()->pixelMetric(
|
||||||
|
QStyle::PM_ButtonShiftVertical, &option, this );
|
||||||
|
|
||||||
|
r.translate( ph, pv );
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Paint event handler
|
||||||
|
\param event Paint event
|
||||||
|
*/
|
||||||
|
void QwtArrowButton::paintEvent( QPaintEvent *event )
|
||||||
|
{
|
||||||
|
QPushButton::paintEvent( event );
|
||||||
|
QPainter painter( this );
|
||||||
|
drawButtonLabel( &painter );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the button label
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\sa The Qt Manual for QPushButton
|
||||||
|
*/
|
||||||
|
void QwtArrowButton::drawButtonLabel( QPainter *painter )
|
||||||
|
{
|
||||||
|
const bool isVertical = d_data->arrowType == Qt::UpArrow ||
|
||||||
|
d_data->arrowType == Qt::DownArrow;
|
||||||
|
|
||||||
|
const QRect r = labelRect();
|
||||||
|
QSize boundingSize = labelRect().size();
|
||||||
|
if ( isVertical )
|
||||||
|
boundingSize.transpose();
|
||||||
|
|
||||||
|
const int w =
|
||||||
|
( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum;
|
||||||
|
|
||||||
|
QSize arrow = arrowSize( Qt::RightArrow,
|
||||||
|
QSize( w, boundingSize.height() ) );
|
||||||
|
|
||||||
|
if ( isVertical )
|
||||||
|
arrow.transpose();
|
||||||
|
|
||||||
|
QRect contentsSize; // aligned rect where to paint all arrows
|
||||||
|
if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow )
|
||||||
|
{
|
||||||
|
contentsSize.setWidth( d_data->num * arrow.width()
|
||||||
|
+ ( d_data->num - 1 ) * Spacing );
|
||||||
|
contentsSize.setHeight( arrow.height() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contentsSize.setWidth( arrow.width() );
|
||||||
|
contentsSize.setHeight( d_data->num * arrow.height()
|
||||||
|
+ ( d_data->num - 1 ) * Spacing );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect arrowRect( contentsSize );
|
||||||
|
arrowRect.moveCenter( r.center() );
|
||||||
|
arrowRect.setSize( arrow );
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
for ( int i = 0; i < d_data->num; i++ )
|
||||||
|
{
|
||||||
|
drawArrow( painter, arrowRect, d_data->arrowType );
|
||||||
|
|
||||||
|
int dx = 0;
|
||||||
|
int dy = 0;
|
||||||
|
|
||||||
|
if ( isVertical )
|
||||||
|
dy = arrow.height() + Spacing;
|
||||||
|
else
|
||||||
|
dx = arrow.width() + Spacing;
|
||||||
|
|
||||||
|
arrowRect.translate( dx, dy );
|
||||||
|
}
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
if ( hasFocus() )
|
||||||
|
{
|
||||||
|
QStyleOptionFocusRect option;
|
||||||
|
option.init( this );
|
||||||
|
option.backgroundColor = palette().color( QPalette::Window );
|
||||||
|
|
||||||
|
style()->drawPrimitive( QStyle::PE_FrameFocusRect,
|
||||||
|
&option, painter, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw an arrow int a bounding rectangle
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param r Rectangle where to paint the arrow
|
||||||
|
\param arrowType Arrow type
|
||||||
|
*/
|
||||||
|
void QwtArrowButton::drawArrow( QPainter *painter,
|
||||||
|
const QRect &r, Qt::ArrowType arrowType ) const
|
||||||
|
{
|
||||||
|
QPolygon pa( 3 );
|
||||||
|
|
||||||
|
switch ( arrowType )
|
||||||
|
{
|
||||||
|
case Qt::UpArrow:
|
||||||
|
pa.setPoint( 0, r.bottomLeft() );
|
||||||
|
pa.setPoint( 1, r.bottomRight() );
|
||||||
|
pa.setPoint( 2, r.center().x(), r.top() );
|
||||||
|
break;
|
||||||
|
case Qt::DownArrow:
|
||||||
|
pa.setPoint( 0, r.topLeft() );
|
||||||
|
pa.setPoint( 1, r.topRight() );
|
||||||
|
pa.setPoint( 2, r.center().x(), r.bottom() );
|
||||||
|
break;
|
||||||
|
case Qt::RightArrow:
|
||||||
|
pa.setPoint( 0, r.topLeft() );
|
||||||
|
pa.setPoint( 1, r.bottomLeft() );
|
||||||
|
pa.setPoint( 2, r.right(), r.center().y() );
|
||||||
|
break;
|
||||||
|
case Qt::LeftArrow:
|
||||||
|
pa.setPoint( 0, r.topRight() );
|
||||||
|
pa.setPoint( 1, r.bottomRight() );
|
||||||
|
pa.setPoint( 2, r.left(), r.center().y() );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( palette().brush( QPalette::ButtonText ) );
|
||||||
|
painter->drawPolygon( pa );
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a size hint
|
||||||
|
*/
|
||||||
|
QSize QwtArrowButton::sizeHint() const
|
||||||
|
{
|
||||||
|
const QSize hint = minimumSizeHint();
|
||||||
|
return hint.expandedTo( QApplication::globalStrut() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Return a minimum size hint
|
||||||
|
*/
|
||||||
|
QSize QwtArrowButton::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
const QSize asz = arrowSize( Qt::RightArrow, QSize() );
|
||||||
|
|
||||||
|
QSize sz(
|
||||||
|
2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(),
|
||||||
|
2 * Margin + asz.height()
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow )
|
||||||
|
sz.transpose();
|
||||||
|
|
||||||
|
QStyleOption styleOption;
|
||||||
|
styleOption.init( this );
|
||||||
|
|
||||||
|
sz = style()->sizeFromContents( QStyle::CT_PushButton,
|
||||||
|
&styleOption, sz, this );
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the size for a arrow that fits into a rectangle of a given size
|
||||||
|
|
||||||
|
\param arrowType Arrow type
|
||||||
|
\param boundingSize Bounding size
|
||||||
|
\return Size of the arrow
|
||||||
|
*/
|
||||||
|
QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType,
|
||||||
|
const QSize &boundingSize ) const
|
||||||
|
{
|
||||||
|
QSize bs = boundingSize;
|
||||||
|
if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
|
||||||
|
bs.transpose();
|
||||||
|
|
||||||
|
const int MinLen = 2;
|
||||||
|
const QSize sz = bs.expandedTo(
|
||||||
|
QSize( MinLen, 2 * MinLen - 1 ) ); // minimum
|
||||||
|
|
||||||
|
int w = sz.width();
|
||||||
|
int h = 2 * w - 1;
|
||||||
|
|
||||||
|
if ( h > sz.height() )
|
||||||
|
{
|
||||||
|
h = sz.height();
|
||||||
|
w = ( h + 1 ) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize arrSize( w, h );
|
||||||
|
if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
|
||||||
|
arrSize.transpose();
|
||||||
|
|
||||||
|
return arrSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief autoRepeat for the space keys
|
||||||
|
*/
|
||||||
|
void QwtArrowButton::keyPressEvent( QKeyEvent *event )
|
||||||
|
{
|
||||||
|
if ( event->isAutoRepeat() && event->key() == Qt::Key_Space )
|
||||||
|
Q_EMIT clicked();
|
||||||
|
|
||||||
|
QPushButton::keyPressEvent( event );
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_ARROW_BUTTON_H
|
||||||
|
#define QWT_ARROW_BUTTON_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpushbutton.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Arrow Button
|
||||||
|
|
||||||
|
A push button with one or more filled triangles on its front.
|
||||||
|
An Arrow button can have 1 to 3 arrows in a row, pointing
|
||||||
|
up, down, left or right.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtArrowButton : public QPushButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QwtArrowButton ( int num, Qt::ArrowType, QWidget *parent = NULL );
|
||||||
|
virtual ~QwtArrowButton();
|
||||||
|
|
||||||
|
Qt::ArrowType arrowType() const;
|
||||||
|
int num() const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
virtual QSize minimumSizeHint() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent( QPaintEvent *event );
|
||||||
|
|
||||||
|
virtual void drawButtonLabel( QPainter * );
|
||||||
|
virtual void drawArrow( QPainter *,
|
||||||
|
const QRect &, Qt::ArrowType ) const;
|
||||||
|
virtual QRect labelRect() const;
|
||||||
|
virtual QSize arrowSize( Qt::ArrowType,
|
||||||
|
const QSize &boundingSize ) const;
|
||||||
|
|
||||||
|
virtual void keyPressEvent( QKeyEvent * );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,510 @@
|
|||||||
|
/* -*- 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 "qwt_clipper.h"
|
||||||
|
#include "qwt_point_polar.h"
|
||||||
|
#include <qrect.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040601
|
||||||
|
#define qAtan(x) ::atan(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QwtClip
|
||||||
|
{
|
||||||
|
// some templates used for inlining
|
||||||
|
template <class Point, typename T> class LeftEdge;
|
||||||
|
template <class Point, typename T> class RightEdge;
|
||||||
|
template <class Point, typename T> class TopEdge;
|
||||||
|
template <class Point, typename T> class BottomEdge;
|
||||||
|
|
||||||
|
template <class Point> class PointBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Point, typename Value>
|
||||||
|
class QwtClip::LeftEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline LeftEdge( Value x1, Value, Value, Value ):
|
||||||
|
d_x1( x1 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInside( const Point &p ) const
|
||||||
|
{
|
||||||
|
return p.x() >= d_x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point intersection( const Point &p1, const Point &p2 ) const
|
||||||
|
{
|
||||||
|
double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
|
||||||
|
return Point( d_x1, static_cast< Value >( p2.y() + ( d_x1 - p2.x() ) * dy ) );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const Value d_x1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Point, typename Value>
|
||||||
|
class QwtClip::RightEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline RightEdge( Value, Value x2, Value, Value ):
|
||||||
|
d_x2( x2 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInside( const Point &p ) const
|
||||||
|
{
|
||||||
|
return p.x() <= d_x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point intersection( const Point &p1, const Point &p2 ) const
|
||||||
|
{
|
||||||
|
double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
|
||||||
|
return Point( d_x2, static_cast<Value>( p2.y() + ( d_x2 - p2.x() ) * dy ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Value d_x2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Point, typename Value>
|
||||||
|
class QwtClip::TopEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline TopEdge( Value, Value, Value y1, Value ):
|
||||||
|
d_y1( y1 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInside( const Point &p ) const
|
||||||
|
{
|
||||||
|
return p.y() >= d_y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point intersection( const Point &p1, const Point &p2 ) const
|
||||||
|
{
|
||||||
|
double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
|
||||||
|
return Point( static_cast<Value>( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Value d_y1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Point, typename Value>
|
||||||
|
class QwtClip::BottomEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline BottomEdge( Value, Value, Value, Value y2 ):
|
||||||
|
d_y2( y2 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInside( const Point &p ) const
|
||||||
|
{
|
||||||
|
return p.y() <= d_y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point intersection( const Point &p1, const Point &p2 ) const
|
||||||
|
{
|
||||||
|
double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
|
||||||
|
return Point( static_cast<Value>( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Value d_y2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Point>
|
||||||
|
class QwtClip::PointBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PointBuffer( int capacity = 0 ):
|
||||||
|
m_capacity( 0 ),
|
||||||
|
m_size( 0 ),
|
||||||
|
m_buffer( NULL )
|
||||||
|
{
|
||||||
|
if ( capacity > 0 )
|
||||||
|
reserve( capacity );
|
||||||
|
}
|
||||||
|
|
||||||
|
~PointBuffer()
|
||||||
|
{
|
||||||
|
if ( m_buffer )
|
||||||
|
::free( m_buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setPoints( int numPoints, const Point *points )
|
||||||
|
{
|
||||||
|
reserve( numPoints );
|
||||||
|
|
||||||
|
m_size = numPoints;
|
||||||
|
::memcpy( m_buffer, points, m_size * sizeof( Point ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reset()
|
||||||
|
{
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point *data() const
|
||||||
|
{
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Point &operator[]( int i )
|
||||||
|
{
|
||||||
|
return m_buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Point &operator[]( int i ) const
|
||||||
|
{
|
||||||
|
return m_buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add( const Point &point )
|
||||||
|
{
|
||||||
|
if ( m_capacity <= m_size )
|
||||||
|
reserve( m_size + 1 );
|
||||||
|
|
||||||
|
m_buffer[m_size++] = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void reserve( int size )
|
||||||
|
{
|
||||||
|
if ( m_capacity == 0 )
|
||||||
|
m_capacity = 1;
|
||||||
|
|
||||||
|
while ( m_capacity < size )
|
||||||
|
m_capacity *= 2;
|
||||||
|
|
||||||
|
m_buffer = static_cast<Point *>(
|
||||||
|
::realloc( m_buffer, m_capacity * sizeof( Point ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_capacity;
|
||||||
|
int m_size;
|
||||||
|
Point *m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace QwtClip;
|
||||||
|
|
||||||
|
template <class Polygon, class Rect, class Point, typename T>
|
||||||
|
class QwtPolygonClipper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtPolygonClipper( const Rect &clipRect ):
|
||||||
|
d_clipRect( clipRect )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon clipPolygon( const Polygon &polygon, bool closePolygon ) const
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if ( d_clipRect.contains( polygon.boundingRect() ) )
|
||||||
|
return polygon;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PointBuffer<Point> points1;
|
||||||
|
PointBuffer<Point> points2( qMin( 256, polygon.size() ) );
|
||||||
|
|
||||||
|
points1.setPoints( polygon.size(), polygon.data() );
|
||||||
|
|
||||||
|
clipEdge< LeftEdge<Point, T> >( closePolygon, points1, points2 );
|
||||||
|
clipEdge< RightEdge<Point, T> >( closePolygon, points2, points1 );
|
||||||
|
clipEdge< TopEdge<Point, T> >( closePolygon, points1, points2 );
|
||||||
|
clipEdge< BottomEdge<Point, T> >( closePolygon, points2, points1 );
|
||||||
|
|
||||||
|
Polygon p;
|
||||||
|
p.resize( points1.size() );
|
||||||
|
::memcpy( p.data(), points1.data(), points1.size() * sizeof( Point ) );
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class Edge>
|
||||||
|
inline void clipEdge( bool closePolygon,
|
||||||
|
PointBuffer<Point> &points, PointBuffer<Point> &clippedPoints ) const
|
||||||
|
{
|
||||||
|
clippedPoints.reset();
|
||||||
|
|
||||||
|
if ( points.size() < 2 )
|
||||||
|
{
|
||||||
|
if ( points.size() == 1 )
|
||||||
|
clippedPoints.add( points[0] );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(),
|
||||||
|
d_clipRect.y(), d_clipRect.y() + d_clipRect.height() );
|
||||||
|
|
||||||
|
int lastPos, start;
|
||||||
|
if ( closePolygon )
|
||||||
|
{
|
||||||
|
start = 0;
|
||||||
|
lastPos = points.size() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start = 1;
|
||||||
|
lastPos = 0;
|
||||||
|
|
||||||
|
if ( edge.isInside( points[0] ) )
|
||||||
|
clippedPoints.add( points[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint nPoints = points.size();
|
||||||
|
for ( uint i = start; i < nPoints; i++ )
|
||||||
|
{
|
||||||
|
const Point &p1 = points[i];
|
||||||
|
const Point &p2 = points[lastPos];
|
||||||
|
|
||||||
|
if ( edge.isInside( p1 ) )
|
||||||
|
{
|
||||||
|
if ( edge.isInside( p2 ) )
|
||||||
|
{
|
||||||
|
clippedPoints.add( p1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clippedPoints.add( edge.intersection( p1, p2 ) );
|
||||||
|
clippedPoints.add( p1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( edge.isInside( p2 ) )
|
||||||
|
{
|
||||||
|
clippedPoints.add( edge.intersection( p1, p2 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastPos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Rect d_clipRect;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QwtCircleClipper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtCircleClipper( const QRectF &r );
|
||||||
|
QVector<QwtInterval> clipCircle( const QPointF &, double radius ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Edge
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Top,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
|
||||||
|
NEdges
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<QPointF> cuttingPoints(
|
||||||
|
Edge, const QPointF &pos, double radius ) const;
|
||||||
|
|
||||||
|
double toAngle( const QPointF &, const QPointF & ) const;
|
||||||
|
|
||||||
|
const QRectF d_rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
QwtCircleClipper::QwtCircleClipper( const QRectF &r ):
|
||||||
|
d_rect( r )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QwtInterval> QwtCircleClipper::clipCircle(
|
||||||
|
const QPointF &pos, double radius ) const
|
||||||
|
{
|
||||||
|
QList<QPointF> points;
|
||||||
|
for ( int edge = 0; edge < NEdges; edge++ )
|
||||||
|
points += cuttingPoints( static_cast<Edge>(edge), pos, radius );
|
||||||
|
|
||||||
|
QVector<QwtInterval> intv;
|
||||||
|
if ( points.size() <= 0 )
|
||||||
|
{
|
||||||
|
QRectF cRect( 0, 0, 2 * radius, 2 * radius );
|
||||||
|
cRect.moveCenter( pos );
|
||||||
|
if ( d_rect.contains( cRect ) )
|
||||||
|
intv += QwtInterval( 0.0, 2 * M_PI );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QList<double> angles;
|
||||||
|
for ( int i = 0; i < points.size(); i++ )
|
||||||
|
angles += toAngle( pos, points[i] );
|
||||||
|
qSort( angles );
|
||||||
|
|
||||||
|
const int in = d_rect.contains( qwtPolar2Pos( pos, radius,
|
||||||
|
angles[0] + ( angles[1] - angles[0] ) / 2 ) );
|
||||||
|
|
||||||
|
if ( in )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < angles.size() - 1; i += 2 )
|
||||||
|
intv += QwtInterval( angles[i], angles[i+1] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = 1; i < angles.size() - 1; i += 2 )
|
||||||
|
intv += QwtInterval( angles[i], angles[i+1] );
|
||||||
|
intv += QwtInterval( angles.last(), angles.first() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intv;
|
||||||
|
}
|
||||||
|
|
||||||
|
double QwtCircleClipper::toAngle(
|
||||||
|
const QPointF &from, const QPointF &to ) const
|
||||||
|
{
|
||||||
|
if ( from.x() == to.x() )
|
||||||
|
return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0;
|
||||||
|
|
||||||
|
const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) );
|
||||||
|
|
||||||
|
double angle = qAtan( m );
|
||||||
|
if ( to.x() > from.x() )
|
||||||
|
{
|
||||||
|
if ( to.y() > from.y() )
|
||||||
|
angle = 2 * M_PI - angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( to.y() > from.y() )
|
||||||
|
angle = M_PI + angle;
|
||||||
|
else
|
||||||
|
angle = M_PI - angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPointF> QwtCircleClipper::cuttingPoints(
|
||||||
|
Edge edge, const QPointF &pos, double radius ) const
|
||||||
|
{
|
||||||
|
QList<QPointF> points;
|
||||||
|
|
||||||
|
if ( edge == Left || edge == Right )
|
||||||
|
{
|
||||||
|
const double x = ( edge == Left ) ? d_rect.left() : d_rect.right();
|
||||||
|
if ( qAbs( pos.x() - x ) < radius )
|
||||||
|
{
|
||||||
|
const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) );
|
||||||
|
const double m_y1 = pos.y() + off;
|
||||||
|
if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() )
|
||||||
|
points += QPointF( x, m_y1 );
|
||||||
|
|
||||||
|
const double m_y2 = pos.y() - off;
|
||||||
|
if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() )
|
||||||
|
points += QPointF( x, m_y2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom();
|
||||||
|
if ( qAbs( pos.y() - y ) < radius )
|
||||||
|
{
|
||||||
|
const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) );
|
||||||
|
const double x1 = pos.x() + off;
|
||||||
|
if ( x1 >= d_rect.left() && x1 <= d_rect.right() )
|
||||||
|
points += QPointF( x1, y );
|
||||||
|
|
||||||
|
const double m_x2 = pos.x() - off;
|
||||||
|
if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() )
|
||||||
|
points += QPointF( m_x2, y );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sutherland-Hodgman polygon clipping
|
||||||
|
|
||||||
|
\param clipRect Clip rectangle
|
||||||
|
\param polygon Polygon
|
||||||
|
\param closePolygon True, when the polygon is closed
|
||||||
|
|
||||||
|
\return Clipped polygon
|
||||||
|
*/
|
||||||
|
QPolygon QwtClipper::clipPolygon(
|
||||||
|
const QRectF &clipRect, const QPolygon &polygon, bool closePolygon )
|
||||||
|
{
|
||||||
|
const int minX = qCeil( clipRect.left() );
|
||||||
|
const int maxX = qFloor( clipRect.right() );
|
||||||
|
const int minY = qCeil( clipRect.top() );
|
||||||
|
const int maxY = qFloor( clipRect.bottom() );
|
||||||
|
|
||||||
|
const QRect r( minX, minY, maxX - minX, maxY - minY );
|
||||||
|
|
||||||
|
QwtPolygonClipper<QPolygon, QRect, QPoint, int> clipper( r );
|
||||||
|
return clipper.clipPolygon( polygon, closePolygon );
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
Sutherland-Hodgman polygon clipping
|
||||||
|
|
||||||
|
\param clipRect Clip rectangle
|
||||||
|
\param polygon Polygon
|
||||||
|
\param closePolygon True, when the polygon is closed
|
||||||
|
|
||||||
|
\return Clipped polygon
|
||||||
|
*/
|
||||||
|
QPolygon QwtClipper::clipPolygon(
|
||||||
|
const QRect &clipRect, const QPolygon &polygon, bool closePolygon )
|
||||||
|
{
|
||||||
|
QwtPolygonClipper<QPolygon, QRect, QPoint, int> clipper( clipRect );
|
||||||
|
return clipper.clipPolygon( polygon, closePolygon );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sutherland-Hodgman polygon clipping
|
||||||
|
|
||||||
|
\param clipRect Clip rectangle
|
||||||
|
\param polygon Polygon
|
||||||
|
\param closePolygon True, when the polygon is closed
|
||||||
|
|
||||||
|
\return Clipped polygon
|
||||||
|
*/
|
||||||
|
QPolygonF QwtClipper::clipPolygonF(
|
||||||
|
const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon )
|
||||||
|
{
|
||||||
|
QwtPolygonClipper<QPolygonF, QRectF, QPointF, double> clipper( clipRect );
|
||||||
|
return clipper.clipPolygon( polygon, closePolygon );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Circle clipping
|
||||||
|
|
||||||
|
clipCircle() divides a circle into intervals of angles representing arcs
|
||||||
|
of the circle. When the circle is completely inside the clip rectangle
|
||||||
|
an interval [0.0, 2 * M_PI] is returned.
|
||||||
|
|
||||||
|
\param clipRect Clip rectangle
|
||||||
|
\param center Center of the circle
|
||||||
|
\param radius Radius of the circle
|
||||||
|
|
||||||
|
\return Arcs of the circle
|
||||||
|
*/
|
||||||
|
QVector<QwtInterval> QwtClipper::clipCircle( const QRectF &clipRect,
|
||||||
|
const QPointF ¢er, double radius )
|
||||||
|
{
|
||||||
|
QwtCircleClipper clipper( clipRect );
|
||||||
|
return clipper.clipCircle( center, radius );
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_CLIPPER_H
|
||||||
|
#define QWT_CLIPPER_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include <qpolygon.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
class QRect;
|
||||||
|
class QRectF;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Some clipping algorithms
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtClipper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QPolygon clipPolygon( const QRect &,
|
||||||
|
const QPolygon &, bool closePolygon = false );
|
||||||
|
static QPolygon clipPolygon( const QRectF &,
|
||||||
|
const QPolygon &, bool closePolygon = false );
|
||||||
|
|
||||||
|
static QPolygonF clipPolygonF( const QRectF &,
|
||||||
|
const QPolygonF &, bool closePolygon = false );
|
||||||
|
|
||||||
|
static QVector<QwtInterval> clipCircle(
|
||||||
|
const QRectF &, const QPointF &, double radius );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,499 @@
|
|||||||
|
/* -*- 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 "qwt_color_map.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include <qnumeric.h>
|
||||||
|
|
||||||
|
class QwtLinearColorMap::ColorStops
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColorStops():
|
||||||
|
d_doAlpha( false )
|
||||||
|
{
|
||||||
|
d_stops.reserve( 256 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert( double pos, const QColor &color );
|
||||||
|
QRgb rgb( QwtLinearColorMap::Mode, double pos ) const;
|
||||||
|
|
||||||
|
QVector<double> stops() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class ColorStop
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColorStop():
|
||||||
|
pos( 0.0 ),
|
||||||
|
rgb( 0 )
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
ColorStop( double p, const QColor &c ):
|
||||||
|
pos( p ),
|
||||||
|
rgb( c.rgba() )
|
||||||
|
{
|
||||||
|
r = qRed( rgb );
|
||||||
|
g = qGreen( rgb );
|
||||||
|
b = qBlue( rgb );
|
||||||
|
a = qAlpha( rgb );
|
||||||
|
|
||||||
|
/*
|
||||||
|
when mapping a value to rgb we will have to calcualate:
|
||||||
|
- const int v = int( ( s1.v0 + ratio * s1.vStep ) + 0.5 );
|
||||||
|
|
||||||
|
Thus adding 0.5 ( for rounding ) can be done in advance
|
||||||
|
*/
|
||||||
|
r0 = r + 0.5;
|
||||||
|
g0 = g + 0.5;
|
||||||
|
b0 = b + 0.5;
|
||||||
|
a0 = a + 0.5;
|
||||||
|
|
||||||
|
rStep = gStep = bStep = aStep = 0.0;
|
||||||
|
posStep = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSteps( const ColorStop &nextStop )
|
||||||
|
{
|
||||||
|
rStep = nextStop.r - r;
|
||||||
|
gStep = nextStop.g - g;
|
||||||
|
bStep = nextStop.b - b;
|
||||||
|
aStep = nextStop.a - a;
|
||||||
|
posStep = nextStop.pos - pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
double pos;
|
||||||
|
QRgb rgb;
|
||||||
|
int r, g, b, a;
|
||||||
|
|
||||||
|
// precalculated values
|
||||||
|
double rStep, gStep, bStep, aStep;
|
||||||
|
double r0, g0, b0, a0;
|
||||||
|
double posStep;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int findUpper( double pos ) const;
|
||||||
|
QVector<ColorStop> d_stops;
|
||||||
|
bool d_doAlpha;
|
||||||
|
};
|
||||||
|
|
||||||
|
void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color )
|
||||||
|
{
|
||||||
|
// Lookups need to be very fast, insertions are not so important.
|
||||||
|
// Anyway, a balanced tree is what we need here. TODO ...
|
||||||
|
|
||||||
|
if ( pos < 0.0 || pos > 1.0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
if ( d_stops.size() == 0 )
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
d_stops.resize( 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = findUpper( pos );
|
||||||
|
if ( index == d_stops.size() ||
|
||||||
|
qAbs( d_stops[index].pos - pos ) >= 0.001 )
|
||||||
|
{
|
||||||
|
d_stops.resize( d_stops.size() + 1 );
|
||||||
|
for ( int i = d_stops.size() - 1; i > index; i-- )
|
||||||
|
d_stops[i] = d_stops[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d_stops[index] = ColorStop( pos, color );
|
||||||
|
if ( color.alpha() != 255 )
|
||||||
|
d_doAlpha = true;
|
||||||
|
|
||||||
|
if ( index > 0 )
|
||||||
|
d_stops[index-1].updateSteps( d_stops[index] );
|
||||||
|
|
||||||
|
if ( index < d_stops.size() - 1 )
|
||||||
|
d_stops[index].updateSteps( d_stops[index+1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
|
||||||
|
{
|
||||||
|
QVector<double> positions( d_stops.size() );
|
||||||
|
for ( int i = 0; i < d_stops.size(); i++ )
|
||||||
|
positions[i] = d_stops[i].pos;
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
int n = d_stops.size();
|
||||||
|
|
||||||
|
const ColorStop *stops = d_stops.data();
|
||||||
|
|
||||||
|
while ( n > 0 )
|
||||||
|
{
|
||||||
|
const int half = n >> 1;
|
||||||
|
const int middle = index + half;
|
||||||
|
|
||||||
|
if ( stops[middle].pos <= pos )
|
||||||
|
{
|
||||||
|
index = middle + 1;
|
||||||
|
n -= half + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n = half;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QRgb QwtLinearColorMap::ColorStops::rgb(
|
||||||
|
QwtLinearColorMap::Mode mode, double pos ) const
|
||||||
|
{
|
||||||
|
if ( pos <= 0.0 )
|
||||||
|
return d_stops[0].rgb;
|
||||||
|
if ( pos >= 1.0 )
|
||||||
|
return d_stops[ d_stops.size() - 1 ].rgb;
|
||||||
|
|
||||||
|
const int index = findUpper( pos );
|
||||||
|
if ( mode == FixedColors )
|
||||||
|
{
|
||||||
|
return d_stops[index-1].rgb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ColorStop &s1 = d_stops[index-1];
|
||||||
|
|
||||||
|
const double ratio = ( pos - s1.pos ) / ( s1.posStep );
|
||||||
|
|
||||||
|
const int r = int( s1.r0 + ratio * s1.rStep );
|
||||||
|
const int g = int( s1.g0 + ratio * s1.gStep );
|
||||||
|
const int b = int( s1.b0 + ratio * s1.bStep );
|
||||||
|
|
||||||
|
if ( d_doAlpha )
|
||||||
|
{
|
||||||
|
if ( s1.aStep )
|
||||||
|
{
|
||||||
|
const int a = int( s1.a0 + ratio * s1.aStep );
|
||||||
|
return qRgba( r, g, b, a );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return qRgba( r, g, b, s1.a );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return qRgb( r, g, b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
QwtColorMap::QwtColorMap( Format format ):
|
||||||
|
d_format( format )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtColorMap::~QwtColorMap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build and return a color map of 256 colors
|
||||||
|
|
||||||
|
The color table is needed for rendering indexed images in combination
|
||||||
|
with using colorIndex().
|
||||||
|
|
||||||
|
\param interval Range for the values
|
||||||
|
\return A color table, that can be used for a QImage
|
||||||
|
*/
|
||||||
|
QVector<QRgb> QwtColorMap::colorTable( const QwtInterval &interval ) const
|
||||||
|
{
|
||||||
|
QVector<QRgb> table( 256 );
|
||||||
|
|
||||||
|
if ( interval.isValid() )
|
||||||
|
{
|
||||||
|
const double step = interval.width() / ( table.size() - 1 );
|
||||||
|
for ( int i = 0; i < table.size(); i++ )
|
||||||
|
table[i] = rgb( interval, interval.minValue() + step * i );
|
||||||
|
}
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtLinearColorMap::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColorStops colorStops;
|
||||||
|
QwtLinearColorMap::Mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build a color map with two stops at 0.0 and 1.0. The color
|
||||||
|
at 0.0 is Qt::blue, at 1.0 it is Qt::yellow.
|
||||||
|
|
||||||
|
\param format Preferred format of the color map
|
||||||
|
*/
|
||||||
|
QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ):
|
||||||
|
QwtColorMap( format )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
d_data->mode = ScaledColors;
|
||||||
|
|
||||||
|
setColorInterval( Qt::blue, Qt::yellow );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build a color map with two stops at 0.0 and 1.0.
|
||||||
|
|
||||||
|
\param color1 Color used for the minimum value of the value interval
|
||||||
|
\param color2 Color used for the maximum value of the value interval
|
||||||
|
\param format Preferred format for the color map
|
||||||
|
*/
|
||||||
|
QwtLinearColorMap::QwtLinearColorMap( const QColor &color1,
|
||||||
|
const QColor &color2, QwtColorMap::Format format ):
|
||||||
|
QwtColorMap( format )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
d_data->mode = ScaledColors;
|
||||||
|
setColorInterval( color1, color2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtLinearColorMap::~QwtLinearColorMap()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the mode of the color map
|
||||||
|
|
||||||
|
FixedColors means the color is calculated from the next lower
|
||||||
|
color stop. ScaledColors means the color is calculated
|
||||||
|
by interpolating the colors of the adjacent stops.
|
||||||
|
|
||||||
|
\sa mode()
|
||||||
|
*/
|
||||||
|
void QwtLinearColorMap::setMode( Mode mode )
|
||||||
|
{
|
||||||
|
d_data->mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Mode of the color map
|
||||||
|
\sa setMode()
|
||||||
|
*/
|
||||||
|
QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
|
||||||
|
{
|
||||||
|
return d_data->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the color range
|
||||||
|
|
||||||
|
Add stops at 0.0 and 1.0.
|
||||||
|
|
||||||
|
\param color1 Color used for the minimum value of the value interval
|
||||||
|
\param color2 Color used for the maximum value of the value interval
|
||||||
|
|
||||||
|
\sa color1(), color2()
|
||||||
|
*/
|
||||||
|
void QwtLinearColorMap::setColorInterval(
|
||||||
|
const QColor &color1, const QColor &color2 )
|
||||||
|
{
|
||||||
|
d_data->colorStops = ColorStops();
|
||||||
|
d_data->colorStops.insert( 0.0, color1 );
|
||||||
|
d_data->colorStops.insert( 1.0, color2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Add a color stop
|
||||||
|
|
||||||
|
The value has to be in the range [0.0, 1.0].
|
||||||
|
F.e. a stop at position 17.0 for a range [10.0,20.0] must be
|
||||||
|
passed as: (17.0 - 10.0) / (20.0 - 10.0)
|
||||||
|
|
||||||
|
\param value Value between [0.0, 1.0]
|
||||||
|
\param color Color stop
|
||||||
|
*/
|
||||||
|
void QwtLinearColorMap::addColorStop( double value, const QColor& color )
|
||||||
|
{
|
||||||
|
if ( value >= 0.0 && value <= 1.0 )
|
||||||
|
d_data->colorStops.insert( value, color );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Positions of color stops in increasing order
|
||||||
|
*/
|
||||||
|
QVector<double> QwtLinearColorMap::colorStops() const
|
||||||
|
{
|
||||||
|
return d_data->colorStops.stops();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the first color of the color range
|
||||||
|
\sa setColorInterval()
|
||||||
|
*/
|
||||||
|
QColor QwtLinearColorMap::color1() const
|
||||||
|
{
|
||||||
|
return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the second color of the color range
|
||||||
|
\sa setColorInterval()
|
||||||
|
*/
|
||||||
|
QColor QwtLinearColorMap::color2() const
|
||||||
|
{
|
||||||
|
return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Map a value of a given interval into a RGB value
|
||||||
|
|
||||||
|
\param interval Range for all values
|
||||||
|
\param value Value to map into a RGB value
|
||||||
|
|
||||||
|
\return RGB value for value
|
||||||
|
*/
|
||||||
|
QRgb QwtLinearColorMap::rgb(
|
||||||
|
const QwtInterval &interval, double value ) const
|
||||||
|
{
|
||||||
|
if ( qIsNaN(value) )
|
||||||
|
return 0u;
|
||||||
|
|
||||||
|
const double width = interval.width();
|
||||||
|
if ( width <= 0.0 )
|
||||||
|
return 0u;
|
||||||
|
|
||||||
|
const double ratio = ( value - interval.minValue() ) / width;
|
||||||
|
return d_data->colorStops.rgb( d_data->mode, ratio );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Map a value of a given interval into a color index
|
||||||
|
|
||||||
|
\param interval Range for all values
|
||||||
|
\param value Value to map into a color index
|
||||||
|
|
||||||
|
\return Index, between 0 and 255
|
||||||
|
*/
|
||||||
|
unsigned char QwtLinearColorMap::colorIndex(
|
||||||
|
const QwtInterval &interval, double value ) const
|
||||||
|
{
|
||||||
|
const double width = interval.width();
|
||||||
|
|
||||||
|
if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ( value >= interval.maxValue() )
|
||||||
|
return 255;
|
||||||
|
|
||||||
|
const double ratio = ( value - interval.minValue() ) / width;
|
||||||
|
|
||||||
|
unsigned char index;
|
||||||
|
if ( d_data->mode == FixedColors )
|
||||||
|
index = static_cast<unsigned char>( ratio * 255 ); // always floor
|
||||||
|
else
|
||||||
|
index = static_cast<unsigned char>( ratio * 255 + 0.5 );
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtAlphaColorMap::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QColor color;
|
||||||
|
QRgb rgb;
|
||||||
|
QRgb rgbMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
\param color Color of the map
|
||||||
|
*/
|
||||||
|
QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
|
||||||
|
QwtColorMap( QwtColorMap::RGB )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
setColor( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtAlphaColorMap::~QwtAlphaColorMap()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the color
|
||||||
|
|
||||||
|
\param color Color
|
||||||
|
\sa color()
|
||||||
|
*/
|
||||||
|
void QwtAlphaColorMap::setColor( const QColor &color )
|
||||||
|
{
|
||||||
|
d_data->color = color;
|
||||||
|
d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
|
||||||
|
d_data->rgbMax = d_data->rgb | ( 255 << 24 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the color
|
||||||
|
\sa setColor()
|
||||||
|
*/
|
||||||
|
QColor QwtAlphaColorMap::color() const
|
||||||
|
{
|
||||||
|
return d_data->color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Map a value of a given interval into a alpha value
|
||||||
|
|
||||||
|
alpha := (value - interval.minValue()) / interval.width();
|
||||||
|
|
||||||
|
\param interval Range for all values
|
||||||
|
\param value Value to map into a RGB value
|
||||||
|
\return RGB value, with an alpha value
|
||||||
|
*/
|
||||||
|
QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const
|
||||||
|
{
|
||||||
|
if ( qIsNaN(value) )
|
||||||
|
return 0u;
|
||||||
|
|
||||||
|
const double width = interval.width();
|
||||||
|
if ( width <= 0.0 )
|
||||||
|
return 0u;
|
||||||
|
|
||||||
|
if ( value <= interval.minValue() )
|
||||||
|
return d_data->rgb;
|
||||||
|
|
||||||
|
if ( value >= interval.maxValue() )
|
||||||
|
return d_data->rgbMax;
|
||||||
|
|
||||||
|
const double ratio = ( value - interval.minValue() ) / width;
|
||||||
|
return d_data->rgb | ( qRound( 255 * ratio ) << 24 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Dummy function, needed to be implemented as it is pure virtual
|
||||||
|
in QwtColorMap. Color indices make no sense in combination with
|
||||||
|
an alpha channel.
|
||||||
|
|
||||||
|
\return Always 0
|
||||||
|
*/
|
||||||
|
unsigned char QwtAlphaColorMap::colorIndex(
|
||||||
|
const QwtInterval &, double ) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,202 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_COLOR_MAP_H
|
||||||
|
#define QWT_COLOR_MAP_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include <qcolor.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief QwtColorMap is used to map values into colors.
|
||||||
|
|
||||||
|
For displaying 3D data on a 2D plane the 3rd dimension is often
|
||||||
|
displayed using colors, like f.e in a spectrogram.
|
||||||
|
|
||||||
|
Each color map is optimized to return colors for only one of the
|
||||||
|
following image formats:
|
||||||
|
|
||||||
|
- QImage::Format_Indexed8\n
|
||||||
|
- QImage::Format_ARGB32\n
|
||||||
|
|
||||||
|
\sa QwtPlotSpectrogram, QwtScaleWidget
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtColorMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Format for color mapping
|
||||||
|
\sa rgb(), colorIndex(), colorTable()
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum Format
|
||||||
|
{
|
||||||
|
//! The map is intended to map into RGB values.
|
||||||
|
RGB,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The map is intended to map into 8 bit values, that
|
||||||
|
are indices into the color table.
|
||||||
|
*/
|
||||||
|
Indexed
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtColorMap( Format = QwtColorMap::RGB );
|
||||||
|
virtual ~QwtColorMap();
|
||||||
|
|
||||||
|
Format format() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Map a value of a given interval into a RGB value.
|
||||||
|
|
||||||
|
\param interval Range for the values
|
||||||
|
\param value Value
|
||||||
|
\return RGB value, corresponding to value
|
||||||
|
*/
|
||||||
|
virtual QRgb rgb( const QwtInterval &interval,
|
||||||
|
double value ) const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Map a value of a given interval into a color index
|
||||||
|
|
||||||
|
\param interval Range for the values
|
||||||
|
\param value Value
|
||||||
|
\return color index, corresponding to value
|
||||||
|
*/
|
||||||
|
virtual unsigned char colorIndex(
|
||||||
|
const QwtInterval &interval, double value ) const = 0;
|
||||||
|
|
||||||
|
QColor color( const QwtInterval &, double value ) const;
|
||||||
|
virtual QVector<QRgb> colorTable( const QwtInterval & ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Format d_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief QwtLinearColorMap builds a color map from color stops.
|
||||||
|
|
||||||
|
A color stop is a color at a specific position. The valid
|
||||||
|
range for the positions is [0.0, 1.0]. When mapping a value
|
||||||
|
into a color it is translated into this interval according to mode().
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtLinearColorMap: public QwtColorMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Mode of color map
|
||||||
|
\sa setMode(), mode()
|
||||||
|
*/
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
//! Return the color from the next lower color stop
|
||||||
|
FixedColors,
|
||||||
|
|
||||||
|
//! Interpolating the colors of the adjacent stops.
|
||||||
|
ScaledColors
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtLinearColorMap( QwtColorMap::Format = QwtColorMap::RGB );
|
||||||
|
QwtLinearColorMap( const QColor &color1, const QColor &color2,
|
||||||
|
QwtColorMap::Format = QwtColorMap::RGB );
|
||||||
|
|
||||||
|
virtual ~QwtLinearColorMap();
|
||||||
|
|
||||||
|
void setMode( Mode );
|
||||||
|
Mode mode() const;
|
||||||
|
|
||||||
|
void setColorInterval( const QColor &color1, const QColor &color2 );
|
||||||
|
void addColorStop( double value, const QColor& );
|
||||||
|
QVector<double> colorStops() const;
|
||||||
|
|
||||||
|
QColor color1() const;
|
||||||
|
QColor color2() const;
|
||||||
|
|
||||||
|
virtual QRgb rgb( const QwtInterval &, double value ) const;
|
||||||
|
virtual unsigned char colorIndex(
|
||||||
|
const QwtInterval &, double value ) const;
|
||||||
|
|
||||||
|
class ColorStops;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Disabled copy constructor and operator=
|
||||||
|
QwtLinearColorMap( const QwtLinearColorMap & );
|
||||||
|
QwtLinearColorMap &operator=( const QwtLinearColorMap & );
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief QwtAlphaColorMap varies the alpha value of a color
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtAlphaColorMap: public QwtColorMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtAlphaColorMap( const QColor & = QColor( Qt::gray ) );
|
||||||
|
virtual ~QwtAlphaColorMap();
|
||||||
|
|
||||||
|
void setColor( const QColor & );
|
||||||
|
QColor color() const;
|
||||||
|
|
||||||
|
virtual QRgb rgb( const QwtInterval &, double value ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QwtAlphaColorMap( const QwtAlphaColorMap & );
|
||||||
|
QwtAlphaColorMap &operator=( const QwtAlphaColorMap & );
|
||||||
|
|
||||||
|
virtual unsigned char colorIndex(
|
||||||
|
const QwtInterval &, double value ) const;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Map a value into a color
|
||||||
|
|
||||||
|
\param interval Valid interval for values
|
||||||
|
\param value Value
|
||||||
|
|
||||||
|
\return Color corresponding to value
|
||||||
|
|
||||||
|
\warning This method is slow for Indexed color maps. If it is
|
||||||
|
necessary to map many values, its better to get the
|
||||||
|
color table once and find the color using colorIndex().
|
||||||
|
*/
|
||||||
|
inline QColor QwtColorMap::color(
|
||||||
|
const QwtInterval &interval, double value ) const
|
||||||
|
{
|
||||||
|
if ( d_format == RGB )
|
||||||
|
{
|
||||||
|
return QColor::fromRgba( rgb( interval, value ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const unsigned int index = colorIndex( interval, value );
|
||||||
|
|
||||||
|
const QVector<QRgb> rgbTable = colorTable( interval );
|
||||||
|
return rgbTable[index]; // slow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Intended format of the color map
|
||||||
|
\sa Format
|
||||||
|
*/
|
||||||
|
inline QwtColorMap::Format QwtColorMap::format() const
|
||||||
|
{
|
||||||
|
return d_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,293 @@
|
|||||||
|
/* -*- 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 "qwt_column_symbol.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
|
||||||
|
static void qwtDrawBox( QPainter *p, const QRectF &rect,
|
||||||
|
const QPalette &pal, double lw )
|
||||||
|
{
|
||||||
|
if ( lw > 0.0 )
|
||||||
|
{
|
||||||
|
if ( rect.width() == 0.0 )
|
||||||
|
{
|
||||||
|
p->setPen( pal.dark().color() );
|
||||||
|
p->drawLine( rect.topLeft(), rect.bottomLeft() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rect.height() == 0.0 )
|
||||||
|
{
|
||||||
|
p->setPen( pal.dark().color() );
|
||||||
|
p->drawLine( rect.topLeft(), rect.topRight() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lw = qMin( lw, rect.height() / 2.0 - 1.0 );
|
||||||
|
lw = qMin( lw, rect.width() / 2.0 - 1.0 );
|
||||||
|
|
||||||
|
const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 );
|
||||||
|
QPolygonF polygon( outerRect );
|
||||||
|
|
||||||
|
if ( outerRect.width() > 2 * lw &&
|
||||||
|
outerRect.height() > 2 * lw )
|
||||||
|
{
|
||||||
|
const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw );
|
||||||
|
polygon = polygon.subtracted( innerRect );
|
||||||
|
}
|
||||||
|
|
||||||
|
p->setPen( Qt::NoPen );
|
||||||
|
|
||||||
|
p->setBrush( pal.dark() );
|
||||||
|
p->drawPolygon( polygon );
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRectF windowRect = rect.adjusted( lw, lw, -lw + 1, -lw + 1 );
|
||||||
|
if ( windowRect.isValid() )
|
||||||
|
p->fillRect( windowRect, pal.window() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qwtDrawPanel( QPainter *painter, const QRectF &rect,
|
||||||
|
const QPalette &pal, double lw )
|
||||||
|
{
|
||||||
|
if ( lw > 0.0 )
|
||||||
|
{
|
||||||
|
if ( rect.width() == 0.0 )
|
||||||
|
{
|
||||||
|
painter->setPen( pal.window().color() );
|
||||||
|
painter->drawLine( rect.topLeft(), rect.bottomLeft() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rect.height() == 0.0 )
|
||||||
|
{
|
||||||
|
painter->setPen( pal.window().color() );
|
||||||
|
painter->drawLine( rect.topLeft(), rect.topRight() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lw = qMin( lw, rect.height() / 2.0 - 1.0 );
|
||||||
|
lw = qMin( lw, rect.width() / 2.0 - 1.0 );
|
||||||
|
|
||||||
|
const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 );
|
||||||
|
const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw );
|
||||||
|
|
||||||
|
QPolygonF lines[2];
|
||||||
|
|
||||||
|
lines[0] += outerRect.bottomLeft();
|
||||||
|
lines[0] += outerRect.topLeft();
|
||||||
|
lines[0] += outerRect.topRight();
|
||||||
|
lines[0] += innerRect.topRight();
|
||||||
|
lines[0] += innerRect.topLeft();
|
||||||
|
lines[0] += innerRect.bottomLeft();
|
||||||
|
|
||||||
|
lines[1] += outerRect.topRight();
|
||||||
|
lines[1] += outerRect.bottomRight();
|
||||||
|
lines[1] += outerRect.bottomLeft();
|
||||||
|
lines[1] += innerRect.bottomLeft();
|
||||||
|
lines[1] += innerRect.bottomRight();
|
||||||
|
lines[1] += innerRect.topRight();
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
|
||||||
|
painter->setBrush( pal.light() );
|
||||||
|
painter->drawPolygon( lines[0] );
|
||||||
|
painter->setBrush( pal.dark() );
|
||||||
|
painter->drawPolygon( lines[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->fillRect( rect.adjusted( lw, lw, -lw + 1, -lw + 1 ), pal.window() );
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtColumnSymbol::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
style( QwtColumnSymbol::Box ),
|
||||||
|
frameStyle( QwtColumnSymbol::Raised ),
|
||||||
|
palette( Qt::gray ),
|
||||||
|
lineWidth( 2 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtColumnSymbol::Style style;
|
||||||
|
QwtColumnSymbol::FrameStyle frameStyle;
|
||||||
|
|
||||||
|
QPalette palette;
|
||||||
|
int lineWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\param style Style of the symbol
|
||||||
|
\sa setStyle(), style(), Style
|
||||||
|
*/
|
||||||
|
QwtColumnSymbol::QwtColumnSymbol( Style style )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
d_data->style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtColumnSymbol::~QwtColumnSymbol()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Specify the symbol style
|
||||||
|
|
||||||
|
\param style Style
|
||||||
|
\sa style(), setPalette()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::setStyle( Style style )
|
||||||
|
{
|
||||||
|
d_data->style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Current symbol style
|
||||||
|
\sa setStyle()
|
||||||
|
*/
|
||||||
|
QwtColumnSymbol::Style QwtColumnSymbol::style() const
|
||||||
|
{
|
||||||
|
return d_data->style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign a palette for the symbol
|
||||||
|
|
||||||
|
\param palette Palette
|
||||||
|
\sa palette(), setStyle()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::setPalette( const QPalette &palette )
|
||||||
|
{
|
||||||
|
d_data->palette = palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Current palette
|
||||||
|
\sa setPalette()
|
||||||
|
*/
|
||||||
|
const QPalette& QwtColumnSymbol::palette() const
|
||||||
|
{
|
||||||
|
return d_data->palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the frame, that is used for the Box style.
|
||||||
|
|
||||||
|
\param frameStyle Frame style
|
||||||
|
\sa frameStyle(), setLineWidth(), setStyle()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::setFrameStyle( FrameStyle frameStyle )
|
||||||
|
{
|
||||||
|
d_data->frameStyle = frameStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Current frame style, that is used for the Box style.
|
||||||
|
\sa setFrameStyle(), lineWidth(), setStyle()
|
||||||
|
*/
|
||||||
|
QwtColumnSymbol::FrameStyle QwtColumnSymbol::frameStyle() const
|
||||||
|
{
|
||||||
|
return d_data->frameStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the line width of the frame, that is used for the Box style.
|
||||||
|
|
||||||
|
\param width Width
|
||||||
|
\sa lineWidth(), setFrameStyle()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::setLineWidth( int width )
|
||||||
|
{
|
||||||
|
if ( width < 0 )
|
||||||
|
width = 0;
|
||||||
|
|
||||||
|
d_data->lineWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Line width of the frame, that is used for the Box style.
|
||||||
|
\sa setLineWidth(), frameStyle(), setStyle()
|
||||||
|
*/
|
||||||
|
int QwtColumnSymbol::lineWidth() const
|
||||||
|
{
|
||||||
|
return d_data->lineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the symbol depending on its style.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param rect Directed rectangle
|
||||||
|
|
||||||
|
\sa drawBox()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::draw( QPainter *painter,
|
||||||
|
const QwtColumnRect &rect ) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
switch ( d_data->style )
|
||||||
|
{
|
||||||
|
case QwtColumnSymbol::Box:
|
||||||
|
{
|
||||||
|
drawBox( painter, rect );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the symbol when it is in Box style.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param rect Directed rectangle
|
||||||
|
|
||||||
|
\sa draw()
|
||||||
|
*/
|
||||||
|
void QwtColumnSymbol::drawBox( QPainter *painter,
|
||||||
|
const QwtColumnRect &rect ) const
|
||||||
|
{
|
||||||
|
QRectF r = rect.toRect();
|
||||||
|
if ( QwtPainter::roundingAlignment( painter ) )
|
||||||
|
{
|
||||||
|
r.setLeft( qRound( r.left() ) );
|
||||||
|
r.setRight( qRound( r.right() ) );
|
||||||
|
r.setTop( qRound( r.top() ) );
|
||||||
|
r.setBottom( qRound( r.bottom() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( d_data->frameStyle )
|
||||||
|
{
|
||||||
|
case QwtColumnSymbol::Raised:
|
||||||
|
{
|
||||||
|
qwtDrawPanel( painter, r, d_data->palette, d_data->lineWidth );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtColumnSymbol::Plain:
|
||||||
|
{
|
||||||
|
qwtDrawBox( painter, r, d_data->palette, d_data->lineWidth );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
painter->fillRect( r.adjusted( 0, 0, 1, 1 ), d_data->palette.window() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,161 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_COLUMN_SYMBOL_H
|
||||||
|
#define QWT_COLUMN_SYMBOL_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include <qpen.h>
|
||||||
|
#include <qsize.h>
|
||||||
|
#include <qrect.h>
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
class QPalette;
|
||||||
|
class QRect;
|
||||||
|
class QwtText;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Directed rectangle representing bounding rectangle and orientation
|
||||||
|
of a column.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtColumnRect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Direction of the column
|
||||||
|
enum Direction
|
||||||
|
{
|
||||||
|
//! From left to right
|
||||||
|
LeftToRight,
|
||||||
|
|
||||||
|
//! From right to left
|
||||||
|
RightToLeft,
|
||||||
|
|
||||||
|
//! From bottom to top
|
||||||
|
BottomToTop,
|
||||||
|
|
||||||
|
//! From top to bottom
|
||||||
|
TopToBottom
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Build an rectangle with invalid intervals directed BottomToTop.
|
||||||
|
QwtColumnRect():
|
||||||
|
direction( BottomToTop )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return A normalized QRect built from the intervals
|
||||||
|
QRectF toRect() const
|
||||||
|
{
|
||||||
|
QRectF r( hInterval.minValue(), vInterval.minValue(),
|
||||||
|
hInterval.maxValue() - hInterval.minValue(),
|
||||||
|
vInterval.maxValue() - vInterval.minValue() );
|
||||||
|
r = r.normalized();
|
||||||
|
|
||||||
|
if ( hInterval.borderFlags() & QwtInterval::ExcludeMinimum )
|
||||||
|
r.adjust( 1, 0, 0, 0 );
|
||||||
|
if ( hInterval.borderFlags() & QwtInterval::ExcludeMaximum )
|
||||||
|
r.adjust( 0, 0, -1, 0 );
|
||||||
|
if ( vInterval.borderFlags() & QwtInterval::ExcludeMinimum )
|
||||||
|
r.adjust( 0, 1, 0, 0 );
|
||||||
|
if ( vInterval.borderFlags() & QwtInterval::ExcludeMaximum )
|
||||||
|
r.adjust( 0, 0, 0, -1 );
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Orientation
|
||||||
|
Qt::Orientation orientation() const
|
||||||
|
{
|
||||||
|
if ( direction == LeftToRight || direction == RightToLeft )
|
||||||
|
return Qt::Horizontal;
|
||||||
|
|
||||||
|
return Qt::Vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Interval for the horizontal coordinates
|
||||||
|
QwtInterval hInterval;
|
||||||
|
|
||||||
|
//! Interval for the vertical coordinates
|
||||||
|
QwtInterval vInterval;
|
||||||
|
|
||||||
|
//! Direction
|
||||||
|
Direction direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A drawing primitive for columns
|
||||||
|
class QWT_EXPORT QwtColumnSymbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Style
|
||||||
|
\sa setStyle(), style()
|
||||||
|
*/
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
//! No Style, the symbol draws nothing
|
||||||
|
NoStyle = -1,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The column is painted with a frame depending on the frameStyle()
|
||||||
|
and lineWidth() using the palette().
|
||||||
|
*/
|
||||||
|
Box,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Styles >= QwtColumnSymbol::UserStyle are reserved for derived
|
||||||
|
classes of QwtColumnSymbol that overload draw() with
|
||||||
|
additional application specific symbol types.
|
||||||
|
*/
|
||||||
|
UserStyle = 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Frame Style used in Box style().
|
||||||
|
\sa Style, setFrameStyle(), frameStyle(), setStyle(), setPalette()
|
||||||
|
*/
|
||||||
|
enum FrameStyle
|
||||||
|
{
|
||||||
|
//! No frame
|
||||||
|
NoFrame,
|
||||||
|
|
||||||
|
//! A plain frame style
|
||||||
|
Plain,
|
||||||
|
|
||||||
|
//! A raised frame style
|
||||||
|
Raised
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
QwtColumnSymbol( Style = NoStyle );
|
||||||
|
virtual ~QwtColumnSymbol();
|
||||||
|
|
||||||
|
void setFrameStyle( FrameStyle );
|
||||||
|
FrameStyle frameStyle() const;
|
||||||
|
|
||||||
|
void setLineWidth( int width );
|
||||||
|
int lineWidth() const;
|
||||||
|
|
||||||
|
void setPalette( const QPalette & );
|
||||||
|
const QPalette &palette() const;
|
||||||
|
|
||||||
|
void setStyle( Style );
|
||||||
|
Style style() const;
|
||||||
|
|
||||||
|
virtual void draw( QPainter *, const QwtColumnRect & ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void drawBox( QPainter *, const QwtColumnRect & ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData* d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,308 @@
|
|||||||
|
/* -*- 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 "qwt_compass.h"
|
||||||
|
#include "qwt_compass_rose.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_scale_draw.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_dial_needle.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpixmap.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
|
||||||
|
Initializes a label map for multiples of 45 degrees
|
||||||
|
*/
|
||||||
|
QwtCompassScaleDraw::QwtCompassScaleDraw()
|
||||||
|
{
|
||||||
|
enableComponent( QwtAbstractScaleDraw::Backbone, false );
|
||||||
|
enableComponent( QwtAbstractScaleDraw::Ticks, false );
|
||||||
|
|
||||||
|
d_labelMap.insert( 0.0, QString::fromLatin1( "N" ) );
|
||||||
|
d_labelMap.insert( 45.0, QString::fromLatin1( "NE" ) );
|
||||||
|
d_labelMap.insert( 90.0, QString::fromLatin1( "E" ) );
|
||||||
|
d_labelMap.insert( 135.0, QString::fromLatin1( "SE" ) );
|
||||||
|
d_labelMap.insert( 180.0, QString::fromLatin1( "S" ) );
|
||||||
|
d_labelMap.insert( 225.0, QString::fromLatin1( "SW" ) );
|
||||||
|
d_labelMap.insert( 270.0, QString::fromLatin1( "W" ) );
|
||||||
|
d_labelMap.insert( 315.0, QString::fromLatin1( "NW" ) );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
d_labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) );
|
||||||
|
d_labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) );
|
||||||
|
d_labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) );
|
||||||
|
d_labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) );
|
||||||
|
d_labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) );
|
||||||
|
d_labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) );
|
||||||
|
d_labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) );
|
||||||
|
d_labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
|
||||||
|
\param map Value to label map
|
||||||
|
*/
|
||||||
|
QwtCompassScaleDraw::QwtCompassScaleDraw( const QMap<double, QString> &map ):
|
||||||
|
d_labelMap( map )
|
||||||
|
{
|
||||||
|
enableComponent( QwtAbstractScaleDraw::Backbone, false );
|
||||||
|
enableComponent( QwtAbstractScaleDraw::Ticks, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set a map, mapping values to labels
|
||||||
|
\param map Value to label map
|
||||||
|
|
||||||
|
The values of the major ticks are found by looking into this
|
||||||
|
map. The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
|
||||||
|
|
||||||
|
\warning The map will have no effect for values that are no major
|
||||||
|
tick values. Major ticks can be changed by QwtScaleDraw::setScale
|
||||||
|
|
||||||
|
\sa labelMap(), scaleDraw(), setScale()
|
||||||
|
*/
|
||||||
|
void QwtCompassScaleDraw::setLabelMap( const QMap<double, QString> &map )
|
||||||
|
{
|
||||||
|
d_labelMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return map, mapping values to labels
|
||||||
|
\sa setLabelMap()
|
||||||
|
*/
|
||||||
|
QMap<double, QString> QwtCompassScaleDraw::labelMap() const
|
||||||
|
{
|
||||||
|
return d_labelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Map a value to a corresponding label
|
||||||
|
|
||||||
|
\param value Value that will be mapped
|
||||||
|
|
||||||
|
label() looks in the labelMap() for a corresponding label for value
|
||||||
|
or returns an null text.
|
||||||
|
|
||||||
|
\return Label
|
||||||
|
\sa labelMap(), setLabelMap()
|
||||||
|
*/
|
||||||
|
|
||||||
|
QwtText QwtCompassScaleDraw::label( double value ) const
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
|
||||||
|
value = 0.0;
|
||||||
|
|
||||||
|
if ( value < 0.0 )
|
||||||
|
value += 360.0;
|
||||||
|
|
||||||
|
if ( d_labelMap.contains( value ) )
|
||||||
|
return d_labelMap[value];
|
||||||
|
|
||||||
|
return QwtText();
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtCompass::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
rose( NULL )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PrivateData()
|
||||||
|
{
|
||||||
|
delete rose;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtCompassRose *rose;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
\param parent Parent widget
|
||||||
|
|
||||||
|
Create a compass widget with a scale, no needle and no rose.
|
||||||
|
The default origin is 270.0 with no valid value. It accepts
|
||||||
|
mouse and keyboard inputs and has no step size. The default mode
|
||||||
|
is QwtDial::RotateNeedle.
|
||||||
|
*/
|
||||||
|
QwtCompass::QwtCompass( QWidget* parent ):
|
||||||
|
QwtDial( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
|
||||||
|
setScaleDraw( new QwtCompassScaleDraw() );
|
||||||
|
|
||||||
|
setOrigin( 270.0 );
|
||||||
|
setWrapping( true );
|
||||||
|
|
||||||
|
setScaleMaxMajor( 36 );
|
||||||
|
setScaleMaxMinor( 10 );
|
||||||
|
|
||||||
|
setScale( 0.0, 360.0 ); // degrees as default
|
||||||
|
setTotalSteps( 360 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtCompass::~QwtCompass()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the contents of the scale
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the content circle
|
||||||
|
\param radius Radius of the content circle
|
||||||
|
*/
|
||||||
|
void QwtCompass::drawScaleContents( QPainter *painter,
|
||||||
|
const QPointF ¢er, double radius ) const
|
||||||
|
{
|
||||||
|
QPalette::ColorGroup cg;
|
||||||
|
if ( isEnabled() )
|
||||||
|
cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
|
||||||
|
else
|
||||||
|
cg = QPalette::Disabled;
|
||||||
|
|
||||||
|
double north = origin();
|
||||||
|
if ( isValid() )
|
||||||
|
{
|
||||||
|
if ( mode() == RotateScale )
|
||||||
|
north -= value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int margin = 4;
|
||||||
|
drawRose( painter, center, radius - margin, 360.0 - north, cg );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the compass rose
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the compass
|
||||||
|
\param radius of the circle, where to paint the rose
|
||||||
|
\param north Direction pointing north, in degrees counter clockwise
|
||||||
|
\param cg Color group
|
||||||
|
*/
|
||||||
|
void QwtCompass::drawRose( QPainter *painter, const QPointF ¢er,
|
||||||
|
double radius, double north, QPalette::ColorGroup cg ) const
|
||||||
|
{
|
||||||
|
if ( d_data->rose )
|
||||||
|
d_data->rose->draw( painter, center, radius, north, cg );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set a rose for the compass
|
||||||
|
\param rose Compass rose
|
||||||
|
\warning The rose will be deleted, when a different rose is
|
||||||
|
set or in ~QwtCompass
|
||||||
|
\sa rose()
|
||||||
|
*/
|
||||||
|
void QwtCompass::setRose( QwtCompassRose *rose )
|
||||||
|
{
|
||||||
|
if ( rose != d_data->rose )
|
||||||
|
{
|
||||||
|
if ( d_data->rose )
|
||||||
|
delete d_data->rose;
|
||||||
|
|
||||||
|
d_data->rose = rose;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return rose
|
||||||
|
\sa setRose()
|
||||||
|
*/
|
||||||
|
const QwtCompassRose *QwtCompass::rose() const
|
||||||
|
{
|
||||||
|
return d_data->rose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return rose
|
||||||
|
\sa setRose()
|
||||||
|
*/
|
||||||
|
QwtCompassRose *QwtCompass::rose()
|
||||||
|
{
|
||||||
|
return d_data->rose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handles key events
|
||||||
|
|
||||||
|
Beside the keys described in QwtDial::keyPressEvent numbers
|
||||||
|
from 1-9 (without 5) set the direction according to their
|
||||||
|
position on the num pad.
|
||||||
|
|
||||||
|
\sa isReadOnly()
|
||||||
|
*/
|
||||||
|
void QwtCompass::keyPressEvent( QKeyEvent *kev )
|
||||||
|
{
|
||||||
|
if ( isReadOnly() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if ( kev->key() == Key_5 )
|
||||||
|
{
|
||||||
|
invalidate(); // signal ???
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double newValue = value();
|
||||||
|
|
||||||
|
if ( kev->key() >= Qt::Key_1 && kev->key() <= Qt::Key_9 )
|
||||||
|
{
|
||||||
|
if ( mode() != RotateNeedle || kev->key() == Qt::Key_5 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch ( kev->key() )
|
||||||
|
{
|
||||||
|
case Qt::Key_6:
|
||||||
|
newValue = 180.0 * 0.0;
|
||||||
|
break;
|
||||||
|
case Qt::Key_3:
|
||||||
|
newValue = 180.0 * 0.25;
|
||||||
|
break;
|
||||||
|
case Qt::Key_2:
|
||||||
|
newValue = 180.0 * 0.5;
|
||||||
|
break;
|
||||||
|
case Qt::Key_1:
|
||||||
|
newValue = 180.0 * 0.75;
|
||||||
|
break;
|
||||||
|
case Qt::Key_4:
|
||||||
|
newValue = 180.0 * 1.0;
|
||||||
|
break;
|
||||||
|
case Qt::Key_7:
|
||||||
|
newValue = 180.0 * 1.25;
|
||||||
|
break;
|
||||||
|
case Qt::Key_8:
|
||||||
|
newValue = 180.0 * 1.5;
|
||||||
|
break;
|
||||||
|
case Qt::Key_9:
|
||||||
|
newValue = 180.0 * 1.75;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newValue -= origin();
|
||||||
|
setValue( newValue );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QwtDial::keyPressEvent( kev );
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_COMPASS_H
|
||||||
|
#define QWT_COMPASS_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_dial.h"
|
||||||
|
#include "qwt_round_scale_draw.h"
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
|
||||||
|
class QwtCompassRose;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A special scale draw made for QwtCompass
|
||||||
|
|
||||||
|
QwtCompassScaleDraw maps values to strings using
|
||||||
|
a special map, that can be modified by the application
|
||||||
|
|
||||||
|
The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
|
||||||
|
|
||||||
|
\sa QwtCompass
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtCompassScaleDraw: public QwtRoundScaleDraw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QwtCompassScaleDraw();
|
||||||
|
explicit QwtCompassScaleDraw( const QMap<double, QString> &map );
|
||||||
|
|
||||||
|
void setLabelMap( const QMap<double, QString> &map );
|
||||||
|
QMap<double, QString> labelMap() const;
|
||||||
|
|
||||||
|
virtual QwtText label( double value ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<double, QString> d_labelMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A Compass Widget
|
||||||
|
|
||||||
|
QwtCompass is a widget to display and enter directions. It consists
|
||||||
|
of a scale, an optional needle and rose.
|
||||||
|
|
||||||
|
\image html dials1.png
|
||||||
|
|
||||||
|
\note The examples/dials example shows how to use QwtCompass.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtCompass: public QwtDial
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QwtCompass( QWidget* parent = NULL );
|
||||||
|
virtual ~QwtCompass();
|
||||||
|
|
||||||
|
void setRose( QwtCompassRose *rose );
|
||||||
|
const QwtCompassRose *rose() const;
|
||||||
|
QwtCompassRose *rose();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawRose( QPainter *, const QPointF ¢er,
|
||||||
|
double radius, double north, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
virtual void drawScaleContents( QPainter *,
|
||||||
|
const QPointF ¢er, double radius ) const;
|
||||||
|
|
||||||
|
virtual void keyPressEvent( QKeyEvent * );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_COMPASS_ROSE_H
|
||||||
|
#define QWT_COMPASS_ROSE_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpalette.h>
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Abstract base class for a compass rose
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtCompassRose
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Destructor
|
||||||
|
virtual ~QwtCompassRose() {};
|
||||||
|
|
||||||
|
//! Assign a palette
|
||||||
|
virtual void setPalette( const QPalette &p )
|
||||||
|
{
|
||||||
|
d_palette = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Current palette
|
||||||
|
const QPalette &palette() const
|
||||||
|
{
|
||||||
|
return d_palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the rose
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center point
|
||||||
|
\param radius Radius of the rose
|
||||||
|
\param north Position
|
||||||
|
\param colorGroup Color group
|
||||||
|
*/
|
||||||
|
virtual void draw( QPainter *painter,
|
||||||
|
const QPointF ¢er, double radius, double north,
|
||||||
|
QPalette::ColorGroup colorGroup = QPalette::Active ) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPalette d_palette;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A simple rose for QwtCompass
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtSimpleCompassRose: public QwtCompassRose
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtSimpleCompassRose( int numThorns = 8, int numThornLevels = -1 );
|
||||||
|
virtual ~QwtSimpleCompassRose();
|
||||||
|
|
||||||
|
void setWidth( double );
|
||||||
|
double width() const;
|
||||||
|
|
||||||
|
void setNumThorns( int );
|
||||||
|
int numThorns() const;
|
||||||
|
|
||||||
|
void setNumThornLevels( int );
|
||||||
|
int numThornLevels() const;
|
||||||
|
|
||||||
|
void setShrinkFactor( double factor );
|
||||||
|
double shrinkFactor() const;
|
||||||
|
|
||||||
|
virtual void draw( QPainter *, const QPointF ¢er, double radius,
|
||||||
|
double north, QPalette::ColorGroup = QPalette::Active ) const;
|
||||||
|
|
||||||
|
static void drawRose( QPainter *, const QPalette &,
|
||||||
|
const QPointF ¢er, double radius, double north, double width,
|
||||||
|
int numThorns, int numThornLevels, double shrinkFactor );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _QWT_COMPAT_H_
|
||||||
|
#define _QWT_COMPAT_H_
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_interval.h"
|
||||||
|
#include "qwt_point_3d.h"
|
||||||
|
#include <qlist.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
#include <qpoint.h>
|
||||||
|
#include <qsize.h>
|
||||||
|
#include <qrect.h>
|
||||||
|
#include <qpolygon.h>
|
||||||
|
|
||||||
|
// A couple of definition for Qwt5 compatibility
|
||||||
|
|
||||||
|
#define qwtMax qMax
|
||||||
|
#define qwtMin qMin
|
||||||
|
#define qwtAbs qAbs
|
||||||
|
#define qwtRound qRound
|
||||||
|
|
||||||
|
#define QwtArray QVector
|
||||||
|
|
||||||
|
typedef QList<double> QwtValueList;
|
||||||
|
typedef QPointF QwtDoublePoint;
|
||||||
|
typedef QSizeF QwtDoubleSize;
|
||||||
|
typedef QRectF QwtDoubleRect;
|
||||||
|
|
||||||
|
typedef QPolygon QwtPolygon;
|
||||||
|
typedef QPolygonF QwtPolygonF;
|
||||||
|
typedef QwtInterval QwtDoubleInterval;
|
||||||
|
typedef QwtPoint3D QwtDoublePoint3D;
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,784 @@
|
|||||||
|
/* -*- 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 "qwt_arrow_button.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_counter.h"
|
||||||
|
#include <qlayout.h>
|
||||||
|
#include <qlineedit.h>
|
||||||
|
#include <qvalidator.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
|
||||||
|
class QwtCounter::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
minimum( 0.0 ),
|
||||||
|
maximum( 0.0 ),
|
||||||
|
singleStep( 1.0 ),
|
||||||
|
isValid( false ),
|
||||||
|
value( 0.0 ),
|
||||||
|
wrapping( false )
|
||||||
|
{
|
||||||
|
increment[Button1] = 1;
|
||||||
|
increment[Button2] = 10;
|
||||||
|
increment[Button3] = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtArrowButton *buttonDown[ButtonCnt];
|
||||||
|
QwtArrowButton *buttonUp[ButtonCnt];
|
||||||
|
QLineEdit *valueEdit;
|
||||||
|
|
||||||
|
int increment[ButtonCnt];
|
||||||
|
int numButtons;
|
||||||
|
|
||||||
|
double minimum;
|
||||||
|
double maximum;
|
||||||
|
double singleStep;
|
||||||
|
|
||||||
|
bool isValid;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
bool wrapping;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The counter is initialized with a range is set to [0.0, 1.0] with
|
||||||
|
0.01 as single step size. The value is invalid.
|
||||||
|
|
||||||
|
The default number of buttons is set to 2. The default increments are:
|
||||||
|
\li Button 1: 1 step
|
||||||
|
\li Button 2: 10 steps
|
||||||
|
\li Button 3: 100 steps
|
||||||
|
|
||||||
|
\param parent
|
||||||
|
*/
|
||||||
|
QwtCounter::QwtCounter( QWidget *parent ):
|
||||||
|
QWidget( parent )
|
||||||
|
{
|
||||||
|
initCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtCounter::initCounter()
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout( this );
|
||||||
|
layout->setSpacing( 0 );
|
||||||
|
layout->setMargin( 0 );
|
||||||
|
|
||||||
|
for ( int i = ButtonCnt - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
QwtArrowButton *btn =
|
||||||
|
new QwtArrowButton( i + 1, Qt::DownArrow, this );
|
||||||
|
btn->setFocusPolicy( Qt::NoFocus );
|
||||||
|
btn->installEventFilter( this );
|
||||||
|
layout->addWidget( btn );
|
||||||
|
|
||||||
|
connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
|
||||||
|
connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
|
||||||
|
|
||||||
|
d_data->buttonDown[i] = btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->valueEdit = new QLineEdit( this );
|
||||||
|
d_data->valueEdit->setReadOnly( false );
|
||||||
|
d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
|
||||||
|
layout->addWidget( d_data->valueEdit );
|
||||||
|
|
||||||
|
connect( d_data->valueEdit, SIGNAL(editingFinished()), SLOT(textChanged()) );
|
||||||
|
|
||||||
|
layout->setStretchFactor( d_data->valueEdit, 10 );
|
||||||
|
|
||||||
|
for ( int i = 0; i < ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
QwtArrowButton *btn =
|
||||||
|
new QwtArrowButton( i + 1, Qt::UpArrow, this );
|
||||||
|
btn->setFocusPolicy( Qt::NoFocus );
|
||||||
|
btn->installEventFilter( this );
|
||||||
|
layout->addWidget( btn );
|
||||||
|
|
||||||
|
connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
|
||||||
|
connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
|
||||||
|
|
||||||
|
d_data->buttonUp[i] = btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNumButtons( 2 );
|
||||||
|
setRange( 0.0, 1.0 );
|
||||||
|
setSingleStep( 0.001 );
|
||||||
|
setValue( 0.0 );
|
||||||
|
|
||||||
|
setSizePolicy(
|
||||||
|
QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
|
||||||
|
|
||||||
|
setFocusProxy( d_data->valueEdit );
|
||||||
|
setFocusPolicy( Qt::StrongFocus );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtCounter::~QwtCounter()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the counter to be in valid/invalid state
|
||||||
|
|
||||||
|
When the counter is set to invalid, no numbers are displayed and
|
||||||
|
the buttons are disabled.
|
||||||
|
|
||||||
|
\param on If true the counter will be set as valid
|
||||||
|
|
||||||
|
\sa setValue(), isValid()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setValid( bool on )
|
||||||
|
{
|
||||||
|
if ( on != d_data->isValid )
|
||||||
|
{
|
||||||
|
d_data->isValid = on;
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
|
if ( d_data->isValid )
|
||||||
|
{
|
||||||
|
showNumber( value() );
|
||||||
|
Q_EMIT valueChanged( value() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d_data->valueEdit->setText( QString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, if the value is valid
|
||||||
|
\sa setValid(), setValue()
|
||||||
|
*/
|
||||||
|
bool QwtCounter::isValid() const
|
||||||
|
{
|
||||||
|
return d_data->isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Allow/disallow the user to manually edit the value
|
||||||
|
|
||||||
|
\param on True disable editing
|
||||||
|
\sa isReadOnly()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setReadOnly( bool on )
|
||||||
|
{
|
||||||
|
d_data->valueEdit->setReadOnly( on );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when the line line edit is read only. (default is no)
|
||||||
|
\sa setReadOnly()
|
||||||
|
*/
|
||||||
|
bool QwtCounter::isReadOnly() const
|
||||||
|
{
|
||||||
|
return d_data->valueEdit->isReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set a new value without adjusting to the step raster
|
||||||
|
|
||||||
|
The state of the counter is set to be valid.
|
||||||
|
|
||||||
|
\param value New value
|
||||||
|
|
||||||
|
\sa isValid(), value(), valueChanged()
|
||||||
|
\warning The value is clipped when it lies outside the range.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QwtCounter::setValue( double value )
|
||||||
|
{
|
||||||
|
const double vmin = qMin( d_data->minimum, d_data->maximum );
|
||||||
|
const double vmax = qMax( d_data->minimum, d_data->maximum );
|
||||||
|
|
||||||
|
value = qBound( vmin, value, vmax );
|
||||||
|
|
||||||
|
if ( !d_data->isValid || value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->isValid = true;
|
||||||
|
d_data->value = value;
|
||||||
|
|
||||||
|
showNumber( value );
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
|
Q_EMIT valueChanged( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Current value of the counter
|
||||||
|
\sa setValue(), valueChanged()
|
||||||
|
*/
|
||||||
|
double QwtCounter::value() const
|
||||||
|
{
|
||||||
|
return d_data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the minimum and maximum values
|
||||||
|
|
||||||
|
The maximum is adjusted if necessary to ensure that the range remains valid.
|
||||||
|
The value might be modified to be inside of the range.
|
||||||
|
|
||||||
|
\param min Minimum value
|
||||||
|
\param max Maximum value
|
||||||
|
|
||||||
|
\sa minimum(), maximum()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setRange( double min, double max )
|
||||||
|
{
|
||||||
|
max = qMax( min, max );
|
||||||
|
|
||||||
|
if ( d_data->maximum == max && d_data->minimum == min )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data->minimum = min;
|
||||||
|
d_data->maximum = max;
|
||||||
|
|
||||||
|
setSingleStep( singleStep() );
|
||||||
|
|
||||||
|
const double value = qBound( min, d_data->value, max );
|
||||||
|
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
|
||||||
|
if ( d_data->isValid )
|
||||||
|
{
|
||||||
|
showNumber( value );
|
||||||
|
Q_EMIT valueChanged( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the minimum value of the range
|
||||||
|
|
||||||
|
\param value Minimum value
|
||||||
|
\sa setRange(), setMaximum(), minimum()
|
||||||
|
|
||||||
|
\note The maximum is adjusted if necessary to ensure that the range remains valid.
|
||||||
|
*/
|
||||||
|
void QwtCounter::setMinimum( double value )
|
||||||
|
{
|
||||||
|
setRange( value, maximum() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The minimum of the range
|
||||||
|
\sa setRange(), setMinimum(), maximum()
|
||||||
|
*/
|
||||||
|
double QwtCounter::minimum() const
|
||||||
|
{
|
||||||
|
return d_data->minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the maximum value of the range
|
||||||
|
|
||||||
|
\param value Maximum value
|
||||||
|
\sa setRange(), setMinimum(), maximum()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setMaximum( double value )
|
||||||
|
{
|
||||||
|
setRange( minimum(), value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The maximum of the range
|
||||||
|
\sa setRange(), setMaximum(), minimum()
|
||||||
|
*/
|
||||||
|
double QwtCounter::maximum() const
|
||||||
|
{
|
||||||
|
return d_data->maximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the step size of the counter
|
||||||
|
|
||||||
|
A value <= 0.0 disables stepping
|
||||||
|
|
||||||
|
\param stepSize Single step size
|
||||||
|
\sa singleStep()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setSingleStep( double stepSize )
|
||||||
|
{
|
||||||
|
d_data->singleStep = qMax( stepSize, 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Single step size
|
||||||
|
\sa setSingleStep()
|
||||||
|
*/
|
||||||
|
double QwtCounter::singleStep() const
|
||||||
|
{
|
||||||
|
return d_data->singleStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief En/Disable wrapping
|
||||||
|
|
||||||
|
If wrapping is true stepping up from maximum() value will take
|
||||||
|
you to the minimum() value and vice versa.
|
||||||
|
|
||||||
|
\param on En/Disable wrapping
|
||||||
|
\sa wrapping()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setWrapping( bool on )
|
||||||
|
{
|
||||||
|
d_data->wrapping = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when wrapping is set
|
||||||
|
\sa setWrapping()
|
||||||
|
*/
|
||||||
|
bool QwtCounter::wrapping() const
|
||||||
|
{
|
||||||
|
return d_data->wrapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Specify the number of buttons on each side of the label
|
||||||
|
|
||||||
|
\param numButtons Number of buttons
|
||||||
|
\sa numButtons()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setNumButtons( int numButtons )
|
||||||
|
{
|
||||||
|
if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
if ( i < numButtons )
|
||||||
|
{
|
||||||
|
d_data->buttonDown[i]->show();
|
||||||
|
d_data->buttonUp[i]->show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d_data->buttonDown[i]->hide();
|
||||||
|
d_data->buttonUp[i]->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->numButtons = numButtons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The number of buttons on each side of the widget.
|
||||||
|
\sa setNumButtons()
|
||||||
|
*/
|
||||||
|
int QwtCounter::numButtons() const
|
||||||
|
{
|
||||||
|
return d_data->numButtons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Specify the number of steps by which the value
|
||||||
|
is incremented or decremented when a specified button
|
||||||
|
is pushed.
|
||||||
|
|
||||||
|
\param button Button index
|
||||||
|
\param numSteps Number of steps
|
||||||
|
|
||||||
|
\sa incSteps()
|
||||||
|
*/
|
||||||
|
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
|
||||||
|
{
|
||||||
|
if ( button >= 0 && button < QwtCounter::ButtonCnt )
|
||||||
|
d_data->increment[ button ] = numSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The number of steps by which a specified button increments the value
|
||||||
|
or 0 if the button is invalid.
|
||||||
|
\param button Button index
|
||||||
|
|
||||||
|
\sa setIncSteps()
|
||||||
|
*/
|
||||||
|
int QwtCounter::incSteps( QwtCounter::Button button ) const
|
||||||
|
{
|
||||||
|
if ( button >= 0 && button < QwtCounter::ButtonCnt )
|
||||||
|
return d_data->increment[ button ];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the number of increment steps for button 1
|
||||||
|
\param nSteps Number of steps
|
||||||
|
*/
|
||||||
|
void QwtCounter::setStepButton1( int nSteps )
|
||||||
|
{
|
||||||
|
setIncSteps( QwtCounter::Button1, nSteps );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! returns the number of increment steps for button 1
|
||||||
|
int QwtCounter::stepButton1() const
|
||||||
|
{
|
||||||
|
return incSteps( QwtCounter::Button1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the number of increment steps for button 2
|
||||||
|
\param nSteps Number of steps
|
||||||
|
*/
|
||||||
|
void QwtCounter::setStepButton2( int nSteps )
|
||||||
|
{
|
||||||
|
setIncSteps( QwtCounter::Button2, nSteps );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! returns the number of increment steps for button 2
|
||||||
|
int QwtCounter::stepButton2() const
|
||||||
|
{
|
||||||
|
return incSteps( QwtCounter::Button2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the number of increment steps for button 3
|
||||||
|
\param nSteps Number of steps
|
||||||
|
*/
|
||||||
|
void QwtCounter::setStepButton3( int nSteps )
|
||||||
|
{
|
||||||
|
setIncSteps( QwtCounter::Button3, nSteps );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! returns the number of increment steps for button 3
|
||||||
|
int QwtCounter::stepButton3() const
|
||||||
|
{
|
||||||
|
return incSteps( QwtCounter::Button3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Set from lineedit
|
||||||
|
void QwtCounter::textChanged()
|
||||||
|
{
|
||||||
|
bool converted = false;
|
||||||
|
|
||||||
|
const double value = d_data->valueEdit->text().toDouble( &converted );
|
||||||
|
if ( converted )
|
||||||
|
setValue( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle QEvent::PolishRequest events
|
||||||
|
\param event Event
|
||||||
|
\return see QWidget::event()
|
||||||
|
*/
|
||||||
|
bool QwtCounter::event( QEvent *event )
|
||||||
|
{
|
||||||
|
if ( event->type() == QEvent::PolishRequest )
|
||||||
|
{
|
||||||
|
const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
|
||||||
|
for ( int i = 0; i < ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
d_data->buttonDown[i]->setMinimumWidth( w );
|
||||||
|
d_data->buttonUp[i]->setMinimumWidth( w );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::event( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle key events
|
||||||
|
|
||||||
|
- Ctrl + Qt::Key_Home\n
|
||||||
|
Step to minimum()
|
||||||
|
- Ctrl + Qt::Key_End\n
|
||||||
|
Step to maximum()
|
||||||
|
- Qt::Key_Up\n
|
||||||
|
Increment by incSteps(QwtCounter::Button1)
|
||||||
|
- Qt::Key_Down\n
|
||||||
|
Decrement by incSteps(QwtCounter::Button1)
|
||||||
|
- Qt::Key_PageUp\n
|
||||||
|
Increment by incSteps(QwtCounter::Button2)
|
||||||
|
- Qt::Key_PageDown\n
|
||||||
|
Decrement by incSteps(QwtCounter::Button2)
|
||||||
|
- Shift + Qt::Key_PageUp\n
|
||||||
|
Increment by incSteps(QwtCounter::Button3)
|
||||||
|
- Shift + Qt::Key_PageDown\n
|
||||||
|
Decrement by incSteps(QwtCounter::Button3)
|
||||||
|
|
||||||
|
\param event Key event
|
||||||
|
*/
|
||||||
|
void QwtCounter::keyPressEvent ( QKeyEvent *event )
|
||||||
|
{
|
||||||
|
bool accepted = true;
|
||||||
|
|
||||||
|
switch ( event->key() )
|
||||||
|
{
|
||||||
|
case Qt::Key_Home:
|
||||||
|
{
|
||||||
|
if ( event->modifiers() & Qt::ControlModifier )
|
||||||
|
setValue( minimum() );
|
||||||
|
else
|
||||||
|
accepted = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_End:
|
||||||
|
{
|
||||||
|
if ( event->modifiers() & Qt::ControlModifier )
|
||||||
|
setValue( maximum() );
|
||||||
|
else
|
||||||
|
accepted = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Up:
|
||||||
|
{
|
||||||
|
incrementValue( d_data->increment[0] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_Down:
|
||||||
|
{
|
||||||
|
incrementValue( -d_data->increment[0] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::Key_PageUp:
|
||||||
|
case Qt::Key_PageDown:
|
||||||
|
{
|
||||||
|
int increment = d_data->increment[0];
|
||||||
|
if ( d_data->numButtons >= 2 )
|
||||||
|
increment = d_data->increment[1];
|
||||||
|
if ( d_data->numButtons >= 3 )
|
||||||
|
{
|
||||||
|
if ( event->modifiers() & Qt::ShiftModifier )
|
||||||
|
increment = d_data->increment[2];
|
||||||
|
}
|
||||||
|
if ( event->key() == Qt::Key_PageDown )
|
||||||
|
increment = -increment;
|
||||||
|
incrementValue( increment );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( accepted )
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::keyPressEvent ( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle wheel events
|
||||||
|
\param event Wheel event
|
||||||
|
*/
|
||||||
|
void QwtCounter::wheelEvent( QWheelEvent *event )
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if ( d_data->numButtons <= 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int increment = d_data->increment[0];
|
||||||
|
if ( d_data->numButtons >= 2 )
|
||||||
|
{
|
||||||
|
if ( event->modifiers() & Qt::ControlModifier )
|
||||||
|
increment = d_data->increment[1];
|
||||||
|
}
|
||||||
|
if ( d_data->numButtons >= 3 )
|
||||||
|
{
|
||||||
|
if ( event->modifiers() & Qt::ShiftModifier )
|
||||||
|
increment = d_data->increment[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < d_data->numButtons; i++ )
|
||||||
|
{
|
||||||
|
if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
|
||||||
|
d_data->buttonUp[i]->geometry().contains( event->pos() ) )
|
||||||
|
{
|
||||||
|
increment = d_data->increment[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int wheel_delta = 120;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
int delta = event->delta();
|
||||||
|
if ( delta >= 2 * wheel_delta )
|
||||||
|
delta /= 2; // Never saw an abs(delta) < 240
|
||||||
|
#endif
|
||||||
|
|
||||||
|
incrementValue( delta / wheel_delta * increment );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtCounter::incrementValue( int numSteps )
|
||||||
|
{
|
||||||
|
const double min = d_data->minimum;
|
||||||
|
const double max = d_data->maximum;
|
||||||
|
double stepSize = d_data->singleStep;
|
||||||
|
|
||||||
|
if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double value = d_data->value + numSteps * stepSize;
|
||||||
|
|
||||||
|
if ( d_data->wrapping )
|
||||||
|
{
|
||||||
|
const double range = max - min;
|
||||||
|
|
||||||
|
if ( value < min )
|
||||||
|
{
|
||||||
|
value += ::ceil( ( min - value ) / range ) * range;
|
||||||
|
}
|
||||||
|
else if ( value > max )
|
||||||
|
{
|
||||||
|
value -= ::ceil( ( value - max ) / range ) * range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = qBound( min, value, max );
|
||||||
|
}
|
||||||
|
|
||||||
|
value = min + qRound( ( value - min ) / stepSize ) * stepSize;
|
||||||
|
|
||||||
|
if ( stepSize > 1e-12 )
|
||||||
|
{
|
||||||
|
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
|
||||||
|
{
|
||||||
|
// correct rounding error if value = 0
|
||||||
|
value = 0.0;
|
||||||
|
}
|
||||||
|
else if ( qFuzzyCompare( value, max ) )
|
||||||
|
{
|
||||||
|
// correct rounding error at the border
|
||||||
|
value = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( value != d_data->value )
|
||||||
|
{
|
||||||
|
d_data->value = value;
|
||||||
|
showNumber( d_data->value );
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
|
Q_EMIT valueChanged( d_data->value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Update buttons according to the current value
|
||||||
|
|
||||||
|
When the QwtCounter under- or over-flows, the focus is set to the smallest
|
||||||
|
up- or down-button and counting is disabled.
|
||||||
|
|
||||||
|
Counting is re-enabled on a button release event (mouse or space bar).
|
||||||
|
*/
|
||||||
|
void QwtCounter::updateButtons()
|
||||||
|
{
|
||||||
|
if ( d_data->isValid )
|
||||||
|
{
|
||||||
|
// 1. save enabled state of the smallest down- and up-button
|
||||||
|
// 2. change enabled state on under- or over-flow
|
||||||
|
|
||||||
|
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
d_data->buttonDown[i]->setEnabled( value() > minimum() );
|
||||||
|
d_data->buttonUp[i]->setEnabled( value() < maximum() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
d_data->buttonDown[i]->setEnabled( false );
|
||||||
|
d_data->buttonUp[i]->setEnabled( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
Display number string
|
||||||
|
|
||||||
|
\param number Number
|
||||||
|
*/
|
||||||
|
void QwtCounter::showNumber( double number )
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
text.setNum( number );
|
||||||
|
|
||||||
|
const int cursorPos = d_data->valueEdit->cursorPosition();
|
||||||
|
d_data->valueEdit->setText( text );
|
||||||
|
d_data->valueEdit->setCursorPosition( cursorPos );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Button clicked
|
||||||
|
void QwtCounter::btnClicked()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < ButtonCnt; i++ )
|
||||||
|
{
|
||||||
|
if ( d_data->buttonUp[i] == sender() )
|
||||||
|
incrementValue( d_data->increment[i] );
|
||||||
|
|
||||||
|
if ( d_data->buttonDown[i] == sender() )
|
||||||
|
incrementValue( -d_data->increment[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Button released
|
||||||
|
void QwtCounter::btnReleased()
|
||||||
|
{
|
||||||
|
Q_EMIT buttonReleased( value() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! A size hint
|
||||||
|
QSize QwtCounter::sizeHint() const
|
||||||
|
{
|
||||||
|
QString tmp;
|
||||||
|
|
||||||
|
int w = tmp.setNum( minimum() ).length();
|
||||||
|
int w1 = tmp.setNum( maximum() ).length();
|
||||||
|
if ( w1 > w )
|
||||||
|
w = w1;
|
||||||
|
w1 = tmp.setNum( minimum() + singleStep() ).length();
|
||||||
|
if ( w1 > w )
|
||||||
|
w = w1;
|
||||||
|
w1 = tmp.setNum( maximum() - singleStep() ).length();
|
||||||
|
if ( w1 > w )
|
||||||
|
w = w1;
|
||||||
|
|
||||||
|
tmp.fill( '9', w );
|
||||||
|
|
||||||
|
QFontMetrics fm( d_data->valueEdit->font() );
|
||||||
|
w = fm.width( tmp ) + 2;
|
||||||
|
if ( d_data->valueEdit->hasFrame() )
|
||||||
|
w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
|
||||||
|
|
||||||
|
// Now we replace default sizeHint contribution of d_data->valueEdit by
|
||||||
|
// what we really need.
|
||||||
|
|
||||||
|
w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
|
||||||
|
|
||||||
|
const int h = qMin( QWidget::sizeHint().height(),
|
||||||
|
d_data->valueEdit->minimumSizeHint().height() );
|
||||||
|
return QSize( w, h );
|
||||||
|
}
|
||||||
@ -0,0 +1,161 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_COUNTER_H
|
||||||
|
#define QWT_COUNTER_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qwidget.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The Counter Widget
|
||||||
|
|
||||||
|
A Counter consists of a label displaying a number and
|
||||||
|
one ore more (up to three) push buttons on each side
|
||||||
|
of the label which can be used to increment or decrement
|
||||||
|
the counter's value.
|
||||||
|
|
||||||
|
A counter has a range from a minimum value to a maximum value
|
||||||
|
and a step size. When the wrapping property is set
|
||||||
|
the counter is circular.
|
||||||
|
|
||||||
|
The number of steps by which a button increments or decrements the value
|
||||||
|
can be specified using setIncSteps(). The number of buttons can be
|
||||||
|
changed with setNumButtons().
|
||||||
|
|
||||||
|
Example:
|
||||||
|
\code
|
||||||
|
#include <qwt_counter.h>
|
||||||
|
|
||||||
|
QwtCounter *counter = new QwtCounter(parent);
|
||||||
|
|
||||||
|
counter->setRange(0.0, 100.0); // From 0.0 to 100
|
||||||
|
counter->setSingleStep( 1.0 ); // Step size 1.0
|
||||||
|
counter->setNumButtons(2); // Two buttons each side
|
||||||
|
counter->setIncSteps(QwtCounter::Button1, 1); // Button 1 increments 1 step
|
||||||
|
counter->setIncSteps(QwtCounter::Button2, 20); // Button 2 increments 20 steps
|
||||||
|
|
||||||
|
connect(counter, SIGNAL(valueChanged(double)), myClass, SLOT(newValue(double)));
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtCounter : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( double value READ value WRITE setValue )
|
||||||
|
Q_PROPERTY( double minimum READ minimum WRITE setMinimum )
|
||||||
|
Q_PROPERTY( double maximum READ maximum WRITE setMaximum )
|
||||||
|
Q_PROPERTY( double singleStep READ singleStep WRITE setSingleStep )
|
||||||
|
|
||||||
|
Q_PROPERTY( int numButtons READ numButtons WRITE setNumButtons )
|
||||||
|
Q_PROPERTY( int stepButton1 READ stepButton1 WRITE setStepButton1 )
|
||||||
|
Q_PROPERTY( int stepButton2 READ stepButton2 WRITE setStepButton2 )
|
||||||
|
Q_PROPERTY( int stepButton3 READ stepButton3 WRITE setStepButton3 )
|
||||||
|
|
||||||
|
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
|
||||||
|
Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Button index
|
||||||
|
enum Button
|
||||||
|
{
|
||||||
|
//! Button intended for minor steps
|
||||||
|
Button1,
|
||||||
|
|
||||||
|
//! Button intended for medium steps
|
||||||
|
Button2,
|
||||||
|
|
||||||
|
//! Button intended for large steps
|
||||||
|
Button3,
|
||||||
|
|
||||||
|
//! Number of buttons
|
||||||
|
ButtonCnt
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit QwtCounter( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtCounter();
|
||||||
|
|
||||||
|
void setValid( bool );
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
void setWrapping( bool );
|
||||||
|
bool wrapping() const;
|
||||||
|
|
||||||
|
bool isReadOnly() const;
|
||||||
|
void setReadOnly( bool );
|
||||||
|
|
||||||
|
void setNumButtons( int );
|
||||||
|
int numButtons() const;
|
||||||
|
|
||||||
|
void setIncSteps( QwtCounter::Button, int numSteps );
|
||||||
|
int incSteps( QwtCounter::Button ) const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
|
||||||
|
double singleStep() const;
|
||||||
|
void setSingleStep( double stepSize );
|
||||||
|
|
||||||
|
void setRange( double min, double max );
|
||||||
|
|
||||||
|
double minimum() const;
|
||||||
|
void setMinimum( double );
|
||||||
|
|
||||||
|
double maximum() const;
|
||||||
|
void setMaximum( double );
|
||||||
|
|
||||||
|
void setStepButton1( int nSteps );
|
||||||
|
int stepButton1() const;
|
||||||
|
|
||||||
|
void setStepButton2( int nSteps );
|
||||||
|
int stepButton2() const;
|
||||||
|
|
||||||
|
void setStepButton3( int nSteps );
|
||||||
|
int stepButton3() const;
|
||||||
|
|
||||||
|
double value() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setValue( double );
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/*!
|
||||||
|
This signal is emitted when a button has been released
|
||||||
|
\param value The new value
|
||||||
|
*/
|
||||||
|
void buttonReleased ( double value );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This signal is emitted when the counter's value has changed
|
||||||
|
\param value The new value
|
||||||
|
*/
|
||||||
|
void valueChanged ( double value );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool event( QEvent * );
|
||||||
|
virtual void wheelEvent( QWheelEvent * );
|
||||||
|
virtual void keyPressEvent( QKeyEvent * );
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void btnReleased();
|
||||||
|
void btnClicked();
|
||||||
|
void textChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void incrementValue( int numSteps );
|
||||||
|
void initCounter();
|
||||||
|
void updateButtons();
|
||||||
|
void showNumber( double );
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,454 @@
|
|||||||
|
/* -*- 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 "qwt_curve_fitter.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_spline.h"
|
||||||
|
#include <qstack.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040601
|
||||||
|
#define qFabs(x) ::fabs(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
QwtCurveFitter::QwtCurveFitter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtCurveFitter::~QwtCurveFitter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtSplineCurveFitter::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
fitMode( QwtSplineCurveFitter::Auto ),
|
||||||
|
splineSize( 250 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtSpline spline;
|
||||||
|
QwtSplineCurveFitter::FitMode fitMode;
|
||||||
|
int splineSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
QwtSplineCurveFitter::QwtSplineCurveFitter()
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtSplineCurveFitter::~QwtSplineCurveFitter()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Select the algorithm used for building the spline
|
||||||
|
|
||||||
|
\param mode Mode representing a spline algorithm
|
||||||
|
\sa fitMode()
|
||||||
|
*/
|
||||||
|
void QwtSplineCurveFitter::setFitMode( FitMode mode )
|
||||||
|
{
|
||||||
|
d_data->fitMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Mode representing a spline algorithm
|
||||||
|
\sa setFitMode()
|
||||||
|
*/
|
||||||
|
QwtSplineCurveFitter::FitMode QwtSplineCurveFitter::fitMode() const
|
||||||
|
{
|
||||||
|
return d_data->fitMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign a spline
|
||||||
|
|
||||||
|
\param spline Spline
|
||||||
|
\sa spline()
|
||||||
|
*/
|
||||||
|
void QwtSplineCurveFitter::setSpline( const QwtSpline &spline )
|
||||||
|
{
|
||||||
|
d_data->spline = spline;
|
||||||
|
d_data->spline.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Spline
|
||||||
|
\sa setSpline()
|
||||||
|
*/
|
||||||
|
const QwtSpline &QwtSplineCurveFitter::spline() const
|
||||||
|
{
|
||||||
|
return d_data->spline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Spline
|
||||||
|
\sa setSpline()
|
||||||
|
*/
|
||||||
|
QwtSpline &QwtSplineCurveFitter::spline()
|
||||||
|
{
|
||||||
|
return d_data->spline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign a spline size ( has to be at least 10 points )
|
||||||
|
|
||||||
|
\param splineSize Spline size
|
||||||
|
\sa splineSize()
|
||||||
|
*/
|
||||||
|
void QwtSplineCurveFitter::setSplineSize( int splineSize )
|
||||||
|
{
|
||||||
|
d_data->splineSize = qMax( splineSize, 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Spline size
|
||||||
|
\sa setSplineSize()
|
||||||
|
*/
|
||||||
|
int QwtSplineCurveFitter::splineSize() const
|
||||||
|
{
|
||||||
|
return d_data->splineSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find a curve which has the best fit to a series of data points
|
||||||
|
|
||||||
|
\param points Series of data points
|
||||||
|
\return Curve points
|
||||||
|
*/
|
||||||
|
QPolygonF QwtSplineCurveFitter::fitCurve( const QPolygonF &points ) const
|
||||||
|
{
|
||||||
|
const int size = points.size();
|
||||||
|
if ( size <= 2 )
|
||||||
|
return points;
|
||||||
|
|
||||||
|
FitMode fitMode = d_data->fitMode;
|
||||||
|
if ( fitMode == Auto )
|
||||||
|
{
|
||||||
|
fitMode = Spline;
|
||||||
|
|
||||||
|
const QPointF *p = points.data();
|
||||||
|
for ( int i = 1; i < size; i++ )
|
||||||
|
{
|
||||||
|
if ( p[i].x() <= p[i-1].x() )
|
||||||
|
{
|
||||||
|
fitMode = ParametricSpline;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fitMode == ParametricSpline )
|
||||||
|
return fitParametric( points );
|
||||||
|
else
|
||||||
|
return fitSpline( points );
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF QwtSplineCurveFitter::fitSpline( const QPolygonF &points ) const
|
||||||
|
{
|
||||||
|
d_data->spline.setPoints( points );
|
||||||
|
if ( !d_data->spline.isValid() )
|
||||||
|
return points;
|
||||||
|
|
||||||
|
QPolygonF fittedPoints( d_data->splineSize );
|
||||||
|
|
||||||
|
const double x1 = points[0].x();
|
||||||
|
const double x2 = points[int( points.size() - 1 )].x();
|
||||||
|
const double dx = x2 - x1;
|
||||||
|
const double delta = dx / ( d_data->splineSize - 1 );
|
||||||
|
|
||||||
|
for ( int i = 0; i < d_data->splineSize; i++ )
|
||||||
|
{
|
||||||
|
QPointF &p = fittedPoints[i];
|
||||||
|
|
||||||
|
const double v = x1 + i * delta;
|
||||||
|
const double sv = d_data->spline.value( v );
|
||||||
|
|
||||||
|
p.setX( v );
|
||||||
|
p.setY( sv );
|
||||||
|
}
|
||||||
|
d_data->spline.reset();
|
||||||
|
|
||||||
|
return fittedPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF QwtSplineCurveFitter::fitParametric( const QPolygonF &points ) const
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const int size = points.size();
|
||||||
|
|
||||||
|
QPolygonF fittedPoints( d_data->splineSize );
|
||||||
|
QPolygonF splinePointsX( size );
|
||||||
|
QPolygonF splinePointsY( size );
|
||||||
|
|
||||||
|
const QPointF *p = points.data();
|
||||||
|
QPointF *spX = splinePointsX.data();
|
||||||
|
QPointF *spY = splinePointsY.data();
|
||||||
|
|
||||||
|
double param = 0.0;
|
||||||
|
for ( i = 0; i < size; i++ )
|
||||||
|
{
|
||||||
|
const double x = p[i].x();
|
||||||
|
const double y = p[i].y();
|
||||||
|
if ( i > 0 )
|
||||||
|
{
|
||||||
|
const double delta = qSqrt( qwtSqr( x - spX[i-1].y() )
|
||||||
|
+ qwtSqr( y - spY[i-1].y() ) );
|
||||||
|
param += qMax( delta, 1.0 );
|
||||||
|
}
|
||||||
|
spX[i].setX( param );
|
||||||
|
spX[i].setY( x );
|
||||||
|
spY[i].setX( param );
|
||||||
|
spY[i].setY( y );
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->spline.setPoints( splinePointsX );
|
||||||
|
if ( !d_data->spline.isValid() )
|
||||||
|
return points;
|
||||||
|
|
||||||
|
const double deltaX =
|
||||||
|
splinePointsX[size - 1].x() / ( d_data->splineSize - 1 );
|
||||||
|
for ( i = 0; i < d_data->splineSize; i++ )
|
||||||
|
{
|
||||||
|
const double dtmp = i * deltaX;
|
||||||
|
fittedPoints[i].setX( d_data->spline.value( dtmp ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->spline.setPoints( splinePointsY );
|
||||||
|
if ( !d_data->spline.isValid() )
|
||||||
|
return points;
|
||||||
|
|
||||||
|
const double deltaY =
|
||||||
|
splinePointsY[size - 1].x() / ( d_data->splineSize - 1 );
|
||||||
|
for ( i = 0; i < d_data->splineSize; i++ )
|
||||||
|
{
|
||||||
|
const double dtmp = i * deltaY;
|
||||||
|
fittedPoints[i].setY( d_data->spline.value( dtmp ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return fittedPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtWeedingCurveFitter::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
tolerance( 1.0 ),
|
||||||
|
chunkSize( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
double tolerance;
|
||||||
|
uint chunkSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QwtWeedingCurveFitter::Line
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Line( int i1 = 0, int i2 = 0 ):
|
||||||
|
from( i1 ),
|
||||||
|
to( i2 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int from;
|
||||||
|
int to;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\param tolerance Tolerance
|
||||||
|
\sa setTolerance(), tolerance()
|
||||||
|
*/
|
||||||
|
QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
setTolerance( tolerance );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtWeedingCurveFitter::~QwtWeedingCurveFitter()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the tolerance
|
||||||
|
|
||||||
|
The tolerance is the maximum distance, that is acceptable
|
||||||
|
between the original curve and the smoothed curve.
|
||||||
|
|
||||||
|
Increasing the tolerance will reduce the number of the
|
||||||
|
resulting points.
|
||||||
|
|
||||||
|
\param tolerance Tolerance
|
||||||
|
|
||||||
|
\sa tolerance()
|
||||||
|
*/
|
||||||
|
void QwtWeedingCurveFitter::setTolerance( double tolerance )
|
||||||
|
{
|
||||||
|
d_data->tolerance = qMax( tolerance, 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Tolerance
|
||||||
|
\sa setTolerance()
|
||||||
|
*/
|
||||||
|
double QwtWeedingCurveFitter::tolerance() const
|
||||||
|
{
|
||||||
|
return d_data->tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Limit the number of points passed to a run of the algorithm
|
||||||
|
|
||||||
|
The runtime of the Douglas Peucker algorithm increases non linear
|
||||||
|
with the number of points. For a chunk size > 0 the polygon
|
||||||
|
is split into pieces passed to the algorithm one by one.
|
||||||
|
|
||||||
|
\param numPoints Maximum for the number of points passed to the algorithm
|
||||||
|
|
||||||
|
\sa chunkSize()
|
||||||
|
*/
|
||||||
|
void QwtWeedingCurveFitter::setChunkSize( uint numPoints )
|
||||||
|
{
|
||||||
|
if ( numPoints > 0 )
|
||||||
|
numPoints = qMax( numPoints, 3U );
|
||||||
|
|
||||||
|
d_data->chunkSize = numPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Maximum for the number of points passed to a run
|
||||||
|
of the algorithm - or 0, when unlimited
|
||||||
|
\sa setChunkSize()
|
||||||
|
*/
|
||||||
|
uint QwtWeedingCurveFitter::chunkSize() const
|
||||||
|
{
|
||||||
|
return d_data->chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param points Series of data points
|
||||||
|
\return Curve points
|
||||||
|
*/
|
||||||
|
QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const
|
||||||
|
{
|
||||||
|
if ( points.isEmpty() )
|
||||||
|
return points;
|
||||||
|
|
||||||
|
QPolygonF fittedPoints;
|
||||||
|
if ( d_data->chunkSize == 0 )
|
||||||
|
{
|
||||||
|
fittedPoints = simplify( points );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < points.size(); i += d_data->chunkSize )
|
||||||
|
{
|
||||||
|
const QPolygonF p = points.mid( i, d_data->chunkSize );
|
||||||
|
fittedPoints += simplify( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fittedPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF &points ) const
|
||||||
|
{
|
||||||
|
const double toleranceSqr = d_data->tolerance * d_data->tolerance;
|
||||||
|
|
||||||
|
QStack<Line> stack;
|
||||||
|
stack.reserve( 500 );
|
||||||
|
|
||||||
|
const QPointF *p = points.data();
|
||||||
|
const int nPoints = points.size();
|
||||||
|
|
||||||
|
QVector<bool> usePoint( nPoints, false );
|
||||||
|
|
||||||
|
stack.push( Line( 0, nPoints - 1 ) );
|
||||||
|
|
||||||
|
while ( !stack.isEmpty() )
|
||||||
|
{
|
||||||
|
const Line r = stack.pop();
|
||||||
|
|
||||||
|
// initialize line segment
|
||||||
|
const double vecX = p[r.to].x() - p[r.from].x();
|
||||||
|
const double vecY = p[r.to].y() - p[r.from].y();
|
||||||
|
|
||||||
|
const double vecLength = qSqrt( vecX * vecX + vecY * vecY );
|
||||||
|
|
||||||
|
const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0;
|
||||||
|
const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0;
|
||||||
|
|
||||||
|
double maxDistSqr = 0.0;
|
||||||
|
int nVertexIndexMaxDistance = r.from + 1;
|
||||||
|
for ( int i = r.from + 1; i < r.to; i++ )
|
||||||
|
{
|
||||||
|
//compare to anchor
|
||||||
|
const double fromVecX = p[i].x() - p[r.from].x();
|
||||||
|
const double fromVecY = p[i].y() - p[r.from].y();
|
||||||
|
|
||||||
|
double distToSegmentSqr;
|
||||||
|
if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
|
||||||
|
{
|
||||||
|
distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double toVecX = p[i].x() - p[r.to].x();
|
||||||
|
const double toVecY = p[i].y() - p[r.to].y();
|
||||||
|
const double toVecLength = toVecX * toVecX + toVecY * toVecY;
|
||||||
|
|
||||||
|
const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
|
||||||
|
if ( s < 0.0 )
|
||||||
|
{
|
||||||
|
distToSegmentSqr = toVecLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
distToSegmentSqr = qFabs( toVecLength - s * s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( maxDistSqr < distToSegmentSqr )
|
||||||
|
{
|
||||||
|
maxDistSqr = distToSegmentSqr;
|
||||||
|
nVertexIndexMaxDistance = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( maxDistSqr <= toleranceSqr )
|
||||||
|
{
|
||||||
|
usePoint[r.from] = true;
|
||||||
|
usePoint[r.to] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.push( Line( r.from, nVertexIndexMaxDistance ) );
|
||||||
|
stack.push( Line( nVertexIndexMaxDistance, r.to ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF stripped;
|
||||||
|
for ( int i = 0; i < nPoints; i++ )
|
||||||
|
{
|
||||||
|
if ( usePoint[i] )
|
||||||
|
stripped += p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return stripped;
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_CURVE_FITTER_H
|
||||||
|
#define QWT_CURVE_FITTER_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpolygon.h>
|
||||||
|
#include <qrect.h>
|
||||||
|
|
||||||
|
class QwtSpline;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Abstract base class for a curve fitter
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtCurveFitter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~QwtCurveFitter();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find a curve which has the best fit to a series of data points
|
||||||
|
|
||||||
|
\param polygon Series of data points
|
||||||
|
\return Curve points
|
||||||
|
*/
|
||||||
|
virtual QPolygonF fitCurve( const QPolygonF &polygon ) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QwtCurveFitter();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QwtCurveFitter( const QwtCurveFitter & );
|
||||||
|
QwtCurveFitter &operator=( const QwtCurveFitter & );
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A curve fitter using cubic splines
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtSplineCurveFitter: public QwtCurveFitter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Spline type
|
||||||
|
The default setting is Auto
|
||||||
|
\sa setFitMode(), FitMode()
|
||||||
|
*/
|
||||||
|
enum FitMode
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
Use the default spline algorithm for polygons with
|
||||||
|
increasing x values ( p[i-1] < p[i] ), otherwise use
|
||||||
|
a parametric spline algorithm.
|
||||||
|
*/
|
||||||
|
Auto,
|
||||||
|
|
||||||
|
//! Use a default spline algorithm
|
||||||
|
Spline,
|
||||||
|
|
||||||
|
//! Use a parametric spline algorithm
|
||||||
|
ParametricSpline
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtSplineCurveFitter();
|
||||||
|
virtual ~QwtSplineCurveFitter();
|
||||||
|
|
||||||
|
void setFitMode( FitMode );
|
||||||
|
FitMode fitMode() const;
|
||||||
|
|
||||||
|
void setSpline( const QwtSpline& );
|
||||||
|
const QwtSpline &spline() const;
|
||||||
|
QwtSpline &spline();
|
||||||
|
|
||||||
|
void setSplineSize( int );
|
||||||
|
int splineSize() const;
|
||||||
|
|
||||||
|
virtual QPolygonF fitCurve( const QPolygonF & ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPolygonF fitSpline( const QPolygonF & ) const;
|
||||||
|
QPolygonF fitParametric( const QPolygonF & ) const;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A curve fitter implementing Douglas and Peucker algorithm
|
||||||
|
|
||||||
|
The purpose of the Douglas and Peucker algorithm is that given a 'curve'
|
||||||
|
composed of line segments to find a curve not too dissimilar but that
|
||||||
|
has fewer points. The algorithm defines 'too dissimilar' based on the
|
||||||
|
maximum distance (tolerance) between the original curve and the
|
||||||
|
smoothed curve.
|
||||||
|
|
||||||
|
The runtime of the algorithm increases non linear ( worst case O( n*n ) )
|
||||||
|
and might be very slow for huge polygons. To avoid performance issues
|
||||||
|
it might be useful to split the polygon ( setChunkSize() ) and to run the algorithm
|
||||||
|
for these smaller parts. The disadvantage of having no interpolation
|
||||||
|
at the borders is for most use cases irrelevant.
|
||||||
|
|
||||||
|
The smoothed curve consists of a subset of the points that defined the
|
||||||
|
original curve.
|
||||||
|
|
||||||
|
In opposite to QwtSplineCurveFitter the Douglas and Peucker algorithm reduces
|
||||||
|
the number of points. By adjusting the tolerance parameter according to the
|
||||||
|
axis scales QwtSplineCurveFitter can be used to implement different
|
||||||
|
level of details to speed up painting of curves of many points.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtWeedingCurveFitter: public QwtCurveFitter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtWeedingCurveFitter( double tolerance = 1.0 );
|
||||||
|
virtual ~QwtWeedingCurveFitter();
|
||||||
|
|
||||||
|
void setTolerance( double );
|
||||||
|
double tolerance() const;
|
||||||
|
|
||||||
|
void setChunkSize( uint );
|
||||||
|
uint chunkSize() const;
|
||||||
|
|
||||||
|
virtual QPolygonF fitCurve( const QPolygonF & ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual QPolygonF simplify( const QPolygonF & ) const;
|
||||||
|
|
||||||
|
class Line;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,764 @@
|
|||||||
|
/* -*- 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 "qwt_date.h"
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include <qlocale.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <limits>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
|
||||||
|
typedef qint64 QwtJulianDay;
|
||||||
|
static const QwtJulianDay minJulianDayD = Q_INT64_C( -784350574879 );
|
||||||
|
static const QwtJulianDay maxJulianDayD = Q_INT64_C( 784354017364 );
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// QDate stores the Julian day as unsigned int, but
|
||||||
|
// but it is QDate::fromJulianDay( int ). That's why
|
||||||
|
// we have the range [ 1, INT_MAX ]
|
||||||
|
typedef int QwtJulianDay;
|
||||||
|
static const QwtJulianDay minJulianDayD = 1;
|
||||||
|
static const QwtJulianDay maxJulianDayD = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static QString qwtExpandedFormat( const QString & format,
|
||||||
|
const QDateTime &dateTime, QwtDate::Week0Type week0Type )
|
||||||
|
{
|
||||||
|
const int week = QwtDate::weekNumber( dateTime.date(), week0Type );
|
||||||
|
|
||||||
|
QString weekNo;
|
||||||
|
weekNo.setNum( week );
|
||||||
|
|
||||||
|
QString weekNoWW;
|
||||||
|
if ( weekNo.length() == 1 )
|
||||||
|
weekNoWW += "0";
|
||||||
|
|
||||||
|
weekNoWW += weekNo;
|
||||||
|
|
||||||
|
QString fmt = format;
|
||||||
|
fmt.replace( "ww", weekNoWW );
|
||||||
|
fmt.replace( "w", weekNo );
|
||||||
|
|
||||||
|
if ( week == 1 && dateTime.date().month() != 1 )
|
||||||
|
{
|
||||||
|
// in case of week 1, we might need to increment the year
|
||||||
|
|
||||||
|
static QString s_yyyy = "yyyy";
|
||||||
|
static QString s_yy = "yy";
|
||||||
|
|
||||||
|
// week 1 might start in the previous year
|
||||||
|
|
||||||
|
bool doReplaceYear = fmt.contains( s_yy );
|
||||||
|
|
||||||
|
if ( doReplaceYear )
|
||||||
|
{
|
||||||
|
if ( fmt.contains( 'M' ) )
|
||||||
|
{
|
||||||
|
// in case of also having 'M' we have a conflict about
|
||||||
|
// which year to show
|
||||||
|
|
||||||
|
doReplaceYear = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// in case of also having 'd' or 'dd' we have a conflict about
|
||||||
|
// which year to show
|
||||||
|
|
||||||
|
int numD = 0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < fmt.size(); i++ )
|
||||||
|
{
|
||||||
|
if ( fmt[i] == 'd' )
|
||||||
|
{
|
||||||
|
numD++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( numD > 0 && numD <= 2 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
numD = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( numD > 0 && numD <= 2 )
|
||||||
|
doReplaceYear = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( doReplaceYear )
|
||||||
|
{
|
||||||
|
const QDate dt( dateTime.date().year() + 1, 1, 1 );
|
||||||
|
|
||||||
|
if ( fmt.contains( s_yyyy ) )
|
||||||
|
{
|
||||||
|
fmt.replace( s_yyyy, dt.toString( s_yyyy ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt.replace( s_yy, dt.toString( s_yyyy ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Qt::DayOfWeek qwtFirstDayOfWeek()
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x040800
|
||||||
|
return QLocale().firstDayOfWeek();
|
||||||
|
#else
|
||||||
|
|
||||||
|
switch( QLocale().country() )
|
||||||
|
{
|
||||||
|
case QLocale::Maldives:
|
||||||
|
return Qt::Friday;
|
||||||
|
|
||||||
|
case QLocale::Afghanistan:
|
||||||
|
case QLocale::Algeria:
|
||||||
|
case QLocale::Bahrain:
|
||||||
|
case QLocale::Djibouti:
|
||||||
|
case QLocale::Egypt:
|
||||||
|
case QLocale::Eritrea:
|
||||||
|
case QLocale::Ethiopia:
|
||||||
|
case QLocale::Iran:
|
||||||
|
case QLocale::Iraq:
|
||||||
|
case QLocale::Jordan:
|
||||||
|
case QLocale::Kenya:
|
||||||
|
case QLocale::Kuwait:
|
||||||
|
case QLocale::LibyanArabJamahiriya:
|
||||||
|
case QLocale::Morocco:
|
||||||
|
case QLocale::Oman:
|
||||||
|
case QLocale::Qatar:
|
||||||
|
case QLocale::SaudiArabia:
|
||||||
|
case QLocale::Somalia:
|
||||||
|
case QLocale::Sudan:
|
||||||
|
case QLocale::Tunisia:
|
||||||
|
case QLocale::Yemen:
|
||||||
|
return Qt::Saturday;
|
||||||
|
|
||||||
|
case QLocale::AmericanSamoa:
|
||||||
|
case QLocale::Argentina:
|
||||||
|
case QLocale::Azerbaijan:
|
||||||
|
case QLocale::Botswana:
|
||||||
|
case QLocale::Canada:
|
||||||
|
case QLocale::China:
|
||||||
|
case QLocale::FaroeIslands:
|
||||||
|
case QLocale::Georgia:
|
||||||
|
case QLocale::Greenland:
|
||||||
|
case QLocale::Guam:
|
||||||
|
case QLocale::HongKong:
|
||||||
|
case QLocale::Iceland:
|
||||||
|
case QLocale::India:
|
||||||
|
case QLocale::Ireland:
|
||||||
|
case QLocale::Israel:
|
||||||
|
case QLocale::Jamaica:
|
||||||
|
case QLocale::Japan:
|
||||||
|
case QLocale::Kyrgyzstan:
|
||||||
|
case QLocale::Lao:
|
||||||
|
case QLocale::Malta:
|
||||||
|
case QLocale::MarshallIslands:
|
||||||
|
case QLocale::Macau:
|
||||||
|
case QLocale::Mongolia:
|
||||||
|
case QLocale::NewZealand:
|
||||||
|
case QLocale::NorthernMarianaIslands:
|
||||||
|
case QLocale::Pakistan:
|
||||||
|
case QLocale::Philippines:
|
||||||
|
case QLocale::RepublicOfKorea:
|
||||||
|
case QLocale::Singapore:
|
||||||
|
case QLocale::SyrianArabRepublic:
|
||||||
|
case QLocale::Taiwan:
|
||||||
|
case QLocale::Thailand:
|
||||||
|
case QLocale::TrinidadAndTobago:
|
||||||
|
case QLocale::UnitedStates:
|
||||||
|
case QLocale::UnitedStatesMinorOutlyingIslands:
|
||||||
|
case QLocale::USVirginIslands:
|
||||||
|
case QLocale::Uzbekistan:
|
||||||
|
case QLocale::Zimbabwe:
|
||||||
|
return Qt::Sunday;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Qt::Monday;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void qwtFloorTime(
|
||||||
|
QwtDate::IntervalType intervalType, QDateTime &dt )
|
||||||
|
{
|
||||||
|
// when dt is inside the special hour where DST is ending
|
||||||
|
// an hour is no unique. Therefore we have to
|
||||||
|
// use UTC time.
|
||||||
|
|
||||||
|
const Qt::TimeSpec timeSpec = dt.timeSpec();
|
||||||
|
|
||||||
|
if ( timeSpec == Qt::LocalTime )
|
||||||
|
dt = dt.toTimeSpec( Qt::UTC );
|
||||||
|
|
||||||
|
const QTime t = dt.time();
|
||||||
|
switch( intervalType )
|
||||||
|
{
|
||||||
|
case QwtDate::Second:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( t.hour(), t.minute(), t.second() ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Minute:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( t.hour(), t.minute(), 0 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Hour:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( t.hour(), 0, 0 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( timeSpec == Qt::LocalTime )
|
||||||
|
dt = dt.toTimeSpec( Qt::LocalTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QDateTime qwtToTimeSpec(
|
||||||
|
const QDateTime &dt, Qt::TimeSpec spec )
|
||||||
|
{
|
||||||
|
if ( dt.timeSpec() == spec )
|
||||||
|
return dt;
|
||||||
|
|
||||||
|
const qint64 jd = dt.date().toJulianDay();
|
||||||
|
if ( jd < 0 || jd >= INT_MAX )
|
||||||
|
{
|
||||||
|
// the conversion between local time and UTC
|
||||||
|
// is internally limited. To avoid
|
||||||
|
// overflows we simply ignore the difference
|
||||||
|
// for those dates
|
||||||
|
|
||||||
|
QDateTime dt2 = dt;
|
||||||
|
dt2.setTimeSpec( spec );
|
||||||
|
return dt2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt.toTimeSpec( spec );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
static inline double qwtToJulianDay( int year, int month, int day )
|
||||||
|
{
|
||||||
|
// code from QDate but using doubles to avoid overflows
|
||||||
|
// for large values
|
||||||
|
|
||||||
|
const int m1 = ( month - 14 ) / 12;
|
||||||
|
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
|
||||||
|
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
|
||||||
|
|
||||||
|
return ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
|
||||||
|
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qint64 qwtFloorDiv64( qint64 a, int b )
|
||||||
|
{
|
||||||
|
if ( a < 0 )
|
||||||
|
a -= b - 1;
|
||||||
|
|
||||||
|
return a / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qint64 qwtFloorDiv( int a, int b )
|
||||||
|
{
|
||||||
|
if ( a < 0 )
|
||||||
|
a -= b - 1;
|
||||||
|
|
||||||
|
return a / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline QDate qwtToDate( int year, int month = 1, int day = 1 )
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
return QDate( year, month, day );
|
||||||
|
#else
|
||||||
|
if ( year > 100000 )
|
||||||
|
{
|
||||||
|
// code from QDate but using doubles to avoid overflows
|
||||||
|
// for large values
|
||||||
|
|
||||||
|
const int m1 = ( month - 14 ) / 12;
|
||||||
|
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
|
||||||
|
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
|
||||||
|
|
||||||
|
const double jd = ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
|
||||||
|
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
|
||||||
|
|
||||||
|
if ( jd > maxJulianDayD )
|
||||||
|
{
|
||||||
|
qWarning() << "qwtToDate: overflow";
|
||||||
|
return QDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QDate( year, month, day );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate from double to QDateTime
|
||||||
|
|
||||||
|
\param value Number of milliseconds since the epoch,
|
||||||
|
1970-01-01T00:00:00 UTC
|
||||||
|
\param timeSpec Time specification
|
||||||
|
\return Datetime value
|
||||||
|
|
||||||
|
\sa toDouble(), QDateTime::setMSecsSinceEpoch()
|
||||||
|
\note The return datetime for Qt::OffsetFromUTC will be Qt::UTC
|
||||||
|
*/
|
||||||
|
QDateTime QwtDate::toDateTime( double value, Qt::TimeSpec timeSpec )
|
||||||
|
{
|
||||||
|
const int msecsPerDay = 86400000;
|
||||||
|
|
||||||
|
const double days = static_cast<qint64>( ::floor( value / msecsPerDay ) );
|
||||||
|
|
||||||
|
const double jd = QwtDate::JulianDayForEpoch + days;
|
||||||
|
if ( ( jd > maxJulianDayD ) || ( jd < minJulianDayD ) )
|
||||||
|
{
|
||||||
|
qWarning() << "QwtDate::toDateTime: overflow";
|
||||||
|
return QDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDate d = QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
|
||||||
|
|
||||||
|
const int msecs = static_cast<int>( value - days * msecsPerDay );
|
||||||
|
|
||||||
|
static const QTime timeNull( 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
QDateTime dt( d, timeNull.addMSecs( msecs ), Qt::UTC );
|
||||||
|
|
||||||
|
if ( timeSpec == Qt::LocalTime )
|
||||||
|
dt = qwtToTimeSpec( dt, timeSpec );
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate from QDateTime to double
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\return Number of milliseconds since 1970-01-01T00:00:00 UTC has passed.
|
||||||
|
|
||||||
|
\sa toDateTime(), QDateTime::toMSecsSinceEpoch()
|
||||||
|
\warning For values very far below or above 1970-01-01 UTC rounding errors
|
||||||
|
will happen due to the limited significance of a double.
|
||||||
|
*/
|
||||||
|
double QwtDate::toDouble( const QDateTime &dateTime )
|
||||||
|
{
|
||||||
|
const int msecsPerDay = 86400000;
|
||||||
|
|
||||||
|
const QDateTime dt = qwtToTimeSpec( dateTime, Qt::UTC );
|
||||||
|
|
||||||
|
const double days = dt.date().toJulianDay() - QwtDate::JulianDayForEpoch;
|
||||||
|
|
||||||
|
const QTime time = dt.time();
|
||||||
|
const double secs = 3600.0 * time.hour() +
|
||||||
|
60.0 * time.minute() + time.second();
|
||||||
|
|
||||||
|
return days * msecsPerDay + time.msec() + 1000.0 * secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Ceil a datetime according the interval type
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\param intervalType Interval type, how to ceil.
|
||||||
|
F.e. when intervalType = QwtDate::Months, the result
|
||||||
|
will be ceiled to the next beginning of a month
|
||||||
|
\return Ceiled datetime
|
||||||
|
\sa floor()
|
||||||
|
*/
|
||||||
|
QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType )
|
||||||
|
{
|
||||||
|
if ( dateTime.date() >= QwtDate::maxDate() )
|
||||||
|
return dateTime;
|
||||||
|
|
||||||
|
QDateTime dt = dateTime;
|
||||||
|
|
||||||
|
switch ( intervalType )
|
||||||
|
{
|
||||||
|
case QwtDate::Millisecond:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Second:
|
||||||
|
{
|
||||||
|
qwtFloorTime( QwtDate::Second, dt );
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addSecs( 1 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Minute:
|
||||||
|
{
|
||||||
|
qwtFloorTime( QwtDate::Minute, dt );
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addSecs( 60 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Hour:
|
||||||
|
{
|
||||||
|
qwtFloorTime( QwtDate::Hour, dt );
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addSecs( 3600 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Day:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addDays( 1 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Week:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addDays( 1 );
|
||||||
|
|
||||||
|
int days = qwtFirstDayOfWeek() - dt.date().dayOfWeek();
|
||||||
|
if ( days < 0 )
|
||||||
|
days += 7;
|
||||||
|
|
||||||
|
dt = dt.addDays( days );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Month:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
dt.setDate( qwtToDate( dateTime.date().year(),
|
||||||
|
dateTime.date().month() ) );
|
||||||
|
|
||||||
|
if ( dt < dateTime )
|
||||||
|
dt = dt.addMonths( 1 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Year:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
|
||||||
|
const QDate d = dateTime.date();
|
||||||
|
|
||||||
|
int year = d.year();
|
||||||
|
if ( d.month() > 1 || d.day() > 1 || !dateTime.time().isNull() )
|
||||||
|
year++;
|
||||||
|
|
||||||
|
if ( year == 0 )
|
||||||
|
year++; // there is no year 0
|
||||||
|
|
||||||
|
dt.setDate( qwtToDate( year ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Floor a datetime according the interval type
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\param intervalType Interval type, how to ceil.
|
||||||
|
F.e. when intervalType = QwtDate::Months,
|
||||||
|
the result will be ceiled to the next
|
||||||
|
beginning of a month
|
||||||
|
\return Floored datetime
|
||||||
|
\sa floor()
|
||||||
|
*/
|
||||||
|
QDateTime QwtDate::floor( const QDateTime &dateTime,
|
||||||
|
IntervalType intervalType )
|
||||||
|
{
|
||||||
|
if ( dateTime.date() <= QwtDate::minDate() )
|
||||||
|
return dateTime;
|
||||||
|
|
||||||
|
QDateTime dt = dateTime;
|
||||||
|
|
||||||
|
switch ( intervalType )
|
||||||
|
{
|
||||||
|
case QwtDate::Millisecond:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Second:
|
||||||
|
case QwtDate::Minute:
|
||||||
|
case QwtDate::Hour:
|
||||||
|
{
|
||||||
|
qwtFloorTime( intervalType, dt );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Day:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Week:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
|
||||||
|
int days = dt.date().dayOfWeek() - qwtFirstDayOfWeek();
|
||||||
|
if ( days < 0 )
|
||||||
|
days += 7;
|
||||||
|
|
||||||
|
dt = dt.addDays( -days );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Month:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
|
||||||
|
const QDate date = qwtToDate( dt.date().year(),
|
||||||
|
dt.date().month() );
|
||||||
|
dt.setDate( date );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtDate::Year:
|
||||||
|
{
|
||||||
|
dt.setTime( QTime( 0, 0 ) );
|
||||||
|
|
||||||
|
const QDate date = qwtToDate( dt.date().year() );
|
||||||
|
dt.setDate( date );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Minimum for the supported date range
|
||||||
|
|
||||||
|
The range of valid dates depends on how QDate stores the
|
||||||
|
Julian day internally.
|
||||||
|
|
||||||
|
- For Qt4 it is "Tue Jan 2 -4713"
|
||||||
|
- For Qt5 it is "Thu Jan 1 -2147483648"
|
||||||
|
|
||||||
|
\return minimum of the date range
|
||||||
|
\sa maxDate()
|
||||||
|
*/
|
||||||
|
QDate QwtDate::minDate()
|
||||||
|
{
|
||||||
|
static QDate date;
|
||||||
|
if ( !date.isValid() )
|
||||||
|
date = QDate::fromJulianDay( minJulianDayD );
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Maximum for the supported date range
|
||||||
|
|
||||||
|
The range of valid dates depends on how QDate stores the
|
||||||
|
Julian day internally.
|
||||||
|
|
||||||
|
- For Qt4 it is "Tue Jun 3 5874898"
|
||||||
|
- For Qt5 it is "Tue Dec 31 2147483647"
|
||||||
|
|
||||||
|
\return maximum of the date range
|
||||||
|
\sa minDate()
|
||||||
|
\note The maximum differs between Qt4 and Qt5
|
||||||
|
*/
|
||||||
|
QDate QwtDate::maxDate()
|
||||||
|
{
|
||||||
|
static QDate date;
|
||||||
|
if ( !date.isValid() )
|
||||||
|
date = QDate::fromJulianDay( maxJulianDayD );
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Date of the first day of the first week for a year
|
||||||
|
|
||||||
|
The first day of a week depends on the current locale
|
||||||
|
( QLocale::firstDayOfWeek() ).
|
||||||
|
|
||||||
|
\param year Year
|
||||||
|
\param type Option how to identify the first week
|
||||||
|
\return First day of week 0
|
||||||
|
|
||||||
|
\sa QLocale::firstDayOfWeek(), weekNumber()
|
||||||
|
*/
|
||||||
|
QDate QwtDate::dateOfWeek0( int year, Week0Type type )
|
||||||
|
{
|
||||||
|
const Qt::DayOfWeek firstDayOfWeek = qwtFirstDayOfWeek();
|
||||||
|
|
||||||
|
QDate dt0( year, 1, 1 );
|
||||||
|
|
||||||
|
// floor to the first day of the week
|
||||||
|
int days = dt0.dayOfWeek() - firstDayOfWeek;
|
||||||
|
if ( days < 0 )
|
||||||
|
days += 7;
|
||||||
|
|
||||||
|
dt0 = dt0.addDays( -days );
|
||||||
|
|
||||||
|
if ( type == QwtDate::FirstThursday )
|
||||||
|
{
|
||||||
|
// according to ISO 8601 the first week is defined
|
||||||
|
// by the first thursday.
|
||||||
|
|
||||||
|
int d = Qt::Thursday - firstDayOfWeek;
|
||||||
|
if ( d < 0 )
|
||||||
|
d += 7;
|
||||||
|
|
||||||
|
if ( dt0.addDays( d ).year() < year )
|
||||||
|
dt0 = dt0.addDays( 7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find the week number of a date
|
||||||
|
|
||||||
|
- QwtDate::FirstThursday\n
|
||||||
|
Corresponding to ISO 8601 ( see QDate::weekNumber() ).
|
||||||
|
|
||||||
|
- QwtDate::FirstDay\n
|
||||||
|
Number of weeks that have begun since dateOfWeek0().
|
||||||
|
|
||||||
|
\param date Date
|
||||||
|
\param type Option how to identify the first week
|
||||||
|
|
||||||
|
\return Week number, starting with 1
|
||||||
|
*/
|
||||||
|
int QwtDate::weekNumber( const QDate &date, Week0Type type )
|
||||||
|
{
|
||||||
|
int weekNo;
|
||||||
|
|
||||||
|
if ( type == QwtDate::FirstDay )
|
||||||
|
{
|
||||||
|
QDate day0;
|
||||||
|
|
||||||
|
if ( date.month() == 12 && date.day() >= 24 )
|
||||||
|
{
|
||||||
|
// week 1 usually starts in the previous years.
|
||||||
|
// and we have to check if we are already there
|
||||||
|
|
||||||
|
day0 = dateOfWeek0( date.year() + 1, type );
|
||||||
|
if ( day0.daysTo( date ) < 0 )
|
||||||
|
day0 = dateOfWeek0( date.year(), type );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
day0 = dateOfWeek0( date.year(), type );
|
||||||
|
}
|
||||||
|
|
||||||
|
weekNo = day0.daysTo( date ) / 7 + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weekNo = date.weekNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
return weekNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Offset in seconds from Coordinated Universal Time
|
||||||
|
|
||||||
|
The offset depends on the time specification of dateTime:
|
||||||
|
|
||||||
|
- Qt::UTC
|
||||||
|
0, dateTime has no offset
|
||||||
|
- Qt::OffsetFromUTC
|
||||||
|
returns dateTime.utcOffset()
|
||||||
|
- Qt::LocalTime:
|
||||||
|
number of seconds from the UTC
|
||||||
|
|
||||||
|
For Qt::LocalTime the offset depends on the timezone and
|
||||||
|
daylight savings.
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\return Offset in seconds
|
||||||
|
*/
|
||||||
|
int QwtDate::utcOffset( const QDateTime &dateTime )
|
||||||
|
{
|
||||||
|
int seconds = 0;
|
||||||
|
|
||||||
|
switch( dateTime.timeSpec() )
|
||||||
|
{
|
||||||
|
case Qt::UTC:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::OffsetFromUTC:
|
||||||
|
{
|
||||||
|
seconds = dateTime.utcOffset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const QDateTime dt1( dateTime.date(), dateTime.time(), Qt::UTC );
|
||||||
|
seconds = dateTime.secsTo( dt1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate a datetime into a string
|
||||||
|
|
||||||
|
Beside the format expressions documented in QDateTime::toString()
|
||||||
|
the following expressions are supported:
|
||||||
|
|
||||||
|
- w\n
|
||||||
|
week number: ( 1 - 53 )
|
||||||
|
- ww\n
|
||||||
|
week number with a leading zero ( 01 - 53 )
|
||||||
|
|
||||||
|
As week 1 usually starts in the previous year a special rule
|
||||||
|
is applied for formats, where the year is expected to match the
|
||||||
|
week number - even if the date belongs to the previous year.
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\param format Format string
|
||||||
|
\param week0Type Specification of week 0
|
||||||
|
|
||||||
|
\return Datetime string
|
||||||
|
\sa QDateTime::toString(), weekNumber(), QwtDateScaleDraw
|
||||||
|
*/
|
||||||
|
QString QwtDate::toString( const QDateTime &dateTime,
|
||||||
|
const QString & format, Week0Type week0Type )
|
||||||
|
{
|
||||||
|
QString fmt = format;
|
||||||
|
if ( fmt.contains( 'w' ) )
|
||||||
|
{
|
||||||
|
fmt = qwtExpandedFormat( fmt, dateTime, week0Type );
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateTime.toString( fmt );
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _QWT_DATE_H_
|
||||||
|
#define _QWT_DATE_H_
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qdatetime.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A collection of methods around date/time values
|
||||||
|
|
||||||
|
Qt offers convenient classes for dealing with date/time values,
|
||||||
|
but Qwt uses coordinate systems that are based on doubles.
|
||||||
|
QwtDate offers methods to translate from QDateTime to double and v.v.
|
||||||
|
|
||||||
|
A double is interpreted as the number of milliseconds since
|
||||||
|
1970-01-01T00:00:00 Universal Coordinated Time - also known
|
||||||
|
as "The Epoch".
|
||||||
|
|
||||||
|
While the range of the Julian day in Qt4 is limited to [0, MAX_INT],
|
||||||
|
Qt5 stores it as qint64 offering a huge range of valid dates.
|
||||||
|
As the significance of a double is below this ( assuming a
|
||||||
|
fraction of 52 bits ) the translation is not
|
||||||
|
bijective with rounding errors for dates very far from Epoch.
|
||||||
|
For a resolution of 1 ms those start to happen for dates above the
|
||||||
|
year 144683.
|
||||||
|
|
||||||
|
An axis for a date/time interval is expected to be aligned
|
||||||
|
and divided in time/date units like seconds, minutes, ...
|
||||||
|
QwtDate offers several algorithms that are needed to
|
||||||
|
calculate these axes.
|
||||||
|
|
||||||
|
\sa QwtDateScaleEngine, QwtDateScaleDraw, QDate, QTime
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtDate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
How to identify the first week of year differs between
|
||||||
|
countries.
|
||||||
|
*/
|
||||||
|
enum Week0Type
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
According to ISO 8601 the first week of a year is defined
|
||||||
|
as "the week with the year's first Thursday in it".
|
||||||
|
|
||||||
|
FirstThursday corresponds to the numbering that is
|
||||||
|
implemented in QDate::weekNumber().
|
||||||
|
*/
|
||||||
|
FirstThursday,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
"The week with January 1.1 in it."
|
||||||
|
|
||||||
|
In the U.S. this definition is more common than
|
||||||
|
FirstThursday.
|
||||||
|
*/
|
||||||
|
FirstDay
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Classification of an time interval
|
||||||
|
|
||||||
|
Time intervals needs to be classified to decide how to
|
||||||
|
align and divide it.
|
||||||
|
*/
|
||||||
|
enum IntervalType
|
||||||
|
{
|
||||||
|
//! The interval is related to milliseconds
|
||||||
|
Millisecond,
|
||||||
|
|
||||||
|
//! The interval is related to seconds
|
||||||
|
Second,
|
||||||
|
|
||||||
|
//! The interval is related to minutes
|
||||||
|
Minute,
|
||||||
|
|
||||||
|
//! The interval is related to hours
|
||||||
|
Hour,
|
||||||
|
|
||||||
|
//! The interval is related to days
|
||||||
|
Day,
|
||||||
|
|
||||||
|
//! The interval is related to weeks
|
||||||
|
Week,
|
||||||
|
|
||||||
|
//! The interval is related to months
|
||||||
|
Month,
|
||||||
|
|
||||||
|
//! The interval is related to years
|
||||||
|
Year
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
//! The Julian day of "The Epoch"
|
||||||
|
JulianDayForEpoch = 2440588
|
||||||
|
};
|
||||||
|
|
||||||
|
static QDate minDate();
|
||||||
|
static QDate maxDate();
|
||||||
|
|
||||||
|
static QDateTime toDateTime( double value,
|
||||||
|
Qt::TimeSpec = Qt::UTC );
|
||||||
|
|
||||||
|
static double toDouble( const QDateTime & );
|
||||||
|
|
||||||
|
static QDateTime ceil( const QDateTime &, IntervalType );
|
||||||
|
static QDateTime floor( const QDateTime &, IntervalType );
|
||||||
|
|
||||||
|
static QDate dateOfWeek0( int year, Week0Type );
|
||||||
|
static int weekNumber( const QDate &, Week0Type );
|
||||||
|
|
||||||
|
static int utcOffset( const QDateTime & );
|
||||||
|
|
||||||
|
static QString toString( const QDateTime &,
|
||||||
|
const QString & format, Week0Type );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,278 @@
|
|||||||
|
/* -*- 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 "qwt_date_scale_draw.h"
|
||||||
|
|
||||||
|
class QwtDateScaleDraw::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData( Qt::TimeSpec spec ):
|
||||||
|
timeSpec( spec ),
|
||||||
|
utcOffset( 0 ),
|
||||||
|
week0Type( QwtDate::FirstThursday )
|
||||||
|
{
|
||||||
|
dateFormats[ QwtDate::Millisecond ] = "hh:mm:ss:zzz\nddd dd MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Second ] = "hh:mm:ss\nddd dd MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Minute ] = "hh:mm\nddd dd MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Hour ] = "hh:mm\nddd dd MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Day ] = "ddd dd MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Week ] = "Www yyyy";
|
||||||
|
dateFormats[ QwtDate::Month ] = "MMM yyyy";
|
||||||
|
dateFormats[ QwtDate::Year ] = "yyyy";
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::TimeSpec timeSpec;
|
||||||
|
int utcOffset;
|
||||||
|
QwtDate::Week0Type week0Type;
|
||||||
|
QString dateFormats[ QwtDate::Year + 1 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
|
||||||
|
The default setting is to display tick labels for the
|
||||||
|
given time specification. The first week of a year is defined like
|
||||||
|
for QwtDate::FirstThursday.
|
||||||
|
|
||||||
|
\param timeSpec Time specification
|
||||||
|
|
||||||
|
\sa setTimeSpec(), setWeek0Type()
|
||||||
|
*/
|
||||||
|
QwtDateScaleDraw::QwtDateScaleDraw( Qt::TimeSpec timeSpec )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData( timeSpec );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtDateScaleDraw::~QwtDateScaleDraw()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the time specification used for the tick labels
|
||||||
|
|
||||||
|
\param timeSpec Time specification
|
||||||
|
\sa timeSpec(), setUtcOffset(), toDateTime()
|
||||||
|
*/
|
||||||
|
void QwtDateScaleDraw::setTimeSpec( Qt::TimeSpec timeSpec )
|
||||||
|
{
|
||||||
|
d_data->timeSpec = timeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Time specification used for the tick labels
|
||||||
|
\sa setTimeSpec(), utcOffset(), toDateTime()
|
||||||
|
*/
|
||||||
|
Qt::TimeSpec QwtDateScaleDraw::timeSpec() const
|
||||||
|
{
|
||||||
|
return d_data->timeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the offset in seconds from Coordinated Universal Time
|
||||||
|
|
||||||
|
\param seconds Offset in seconds
|
||||||
|
|
||||||
|
\note The offset has no effect beside for the time specification
|
||||||
|
Qt::OffsetFromUTC.
|
||||||
|
|
||||||
|
\sa QDate::utcOffset(), setTimeSpec(), toDateTime()
|
||||||
|
*/
|
||||||
|
void QwtDateScaleDraw::setUtcOffset( int seconds )
|
||||||
|
{
|
||||||
|
d_data->utcOffset = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Offset in seconds from Coordinated Universal Time
|
||||||
|
\note The offset has no effect beside for the time specification
|
||||||
|
Qt::OffsetFromUTC.
|
||||||
|
|
||||||
|
\sa QDate::setUtcOffset(), setTimeSpec(), toDateTime()
|
||||||
|
*/
|
||||||
|
int QwtDateScaleDraw::utcOffset() const
|
||||||
|
{
|
||||||
|
return d_data->utcOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets how to identify the first week of a year.
|
||||||
|
|
||||||
|
\param week0Type Mode how to identify the first week of a year
|
||||||
|
|
||||||
|
\sa week0Type().
|
||||||
|
\note week0Type has no effect beside for intervals classified as
|
||||||
|
QwtDate::Week.
|
||||||
|
*/
|
||||||
|
void QwtDateScaleDraw::setWeek0Type( QwtDate::Week0Type week0Type )
|
||||||
|
{
|
||||||
|
d_data->week0Type = week0Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Setting how to identify the first week of a year.
|
||||||
|
\sa setWeek0Type()
|
||||||
|
*/
|
||||||
|
QwtDate::Week0Type QwtDateScaleDraw::week0Type() const
|
||||||
|
{
|
||||||
|
return d_data->week0Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the default format string for an datetime interval type
|
||||||
|
|
||||||
|
\param intervalType Interval type
|
||||||
|
\param format Default format string
|
||||||
|
|
||||||
|
\sa dateFormat(), dateFormatOfDate(), QwtDate::toString()
|
||||||
|
*/
|
||||||
|
void QwtDateScaleDraw::setDateFormat(
|
||||||
|
QwtDate::IntervalType intervalType, const QString &format )
|
||||||
|
{
|
||||||
|
if ( intervalType >= QwtDate::Millisecond &&
|
||||||
|
intervalType <= QwtDate::Year )
|
||||||
|
{
|
||||||
|
d_data->dateFormats[ intervalType ] = format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param intervalType Interval type
|
||||||
|
\return Default format string for an datetime interval type
|
||||||
|
\sa setDateFormat(), dateFormatOfDate()
|
||||||
|
*/
|
||||||
|
QString QwtDateScaleDraw::dateFormat(
|
||||||
|
QwtDate::IntervalType intervalType ) const
|
||||||
|
{
|
||||||
|
if ( intervalType >= QwtDate::Millisecond &&
|
||||||
|
intervalType <= QwtDate::Year )
|
||||||
|
{
|
||||||
|
return d_data->dateFormats[ intervalType ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Format string for the representation of a datetime
|
||||||
|
|
||||||
|
dateFormatOfDate() is intended to be overloaded for
|
||||||
|
situations, where formats are individual for specific
|
||||||
|
datetime values.
|
||||||
|
|
||||||
|
The default setting ignores dateTime and return
|
||||||
|
the default format for the interval type.
|
||||||
|
|
||||||
|
\param dateTime Datetime value
|
||||||
|
\param intervalType Interval type
|
||||||
|
\return Format string
|
||||||
|
|
||||||
|
\sa setDateFormat(), QwtDate::toString()
|
||||||
|
*/
|
||||||
|
QString QwtDateScaleDraw::dateFormatOfDate( const QDateTime &dateTime,
|
||||||
|
QwtDate::IntervalType intervalType ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( dateTime )
|
||||||
|
|
||||||
|
if ( intervalType >= QwtDate::Millisecond &&
|
||||||
|
intervalType <= QwtDate::Year )
|
||||||
|
{
|
||||||
|
return d_data->dateFormats[ intervalType ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return d_data->dateFormats[ QwtDate::Second ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Convert a value into its representing label
|
||||||
|
|
||||||
|
The value is converted to a datetime value using toDateTime()
|
||||||
|
and converted to a plain text using QwtDate::toString().
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\return Label string.
|
||||||
|
|
||||||
|
\sa dateFormatOfDate()
|
||||||
|
*/
|
||||||
|
QwtText QwtDateScaleDraw::label( double value ) const
|
||||||
|
{
|
||||||
|
const QDateTime dt = toDateTime( value );
|
||||||
|
const QString fmt = dateFormatOfDate(
|
||||||
|
dt, intervalType( scaleDiv() ) );
|
||||||
|
|
||||||
|
return QwtDate::toString( dt, fmt, d_data->week0Type );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find the less detailed datetime unit, where no rounding
|
||||||
|
errors happen.
|
||||||
|
|
||||||
|
\param scaleDiv Scale division
|
||||||
|
\return Interval type
|
||||||
|
|
||||||
|
\sa dateFormatOfDate()
|
||||||
|
*/
|
||||||
|
QwtDate::IntervalType QwtDateScaleDraw::intervalType(
|
||||||
|
const QwtScaleDiv &scaleDiv ) const
|
||||||
|
{
|
||||||
|
int intvType = QwtDate::Year;
|
||||||
|
|
||||||
|
bool alignedToWeeks = true;
|
||||||
|
|
||||||
|
const QList<double> ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick );
|
||||||
|
for ( int i = 0; i < ticks.size(); i++ )
|
||||||
|
{
|
||||||
|
const QDateTime dt = toDateTime( ticks[i] );
|
||||||
|
for ( int j = QwtDate::Second; j <= intvType; j++ )
|
||||||
|
{
|
||||||
|
const QDateTime dt0 = QwtDate::floor( dt,
|
||||||
|
static_cast<QwtDate::IntervalType>( j ) );
|
||||||
|
|
||||||
|
if ( dt0 != dt )
|
||||||
|
{
|
||||||
|
if ( j == QwtDate::Week )
|
||||||
|
{
|
||||||
|
alignedToWeeks = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
intvType = j - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( intvType == QwtDate::Millisecond )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( intvType == QwtDate::Week && !alignedToWeeks )
|
||||||
|
intvType = QwtDate::Day;
|
||||||
|
|
||||||
|
return static_cast<QwtDate::IntervalType>( intvType );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Translate a double value into a QDateTime object.
|
||||||
|
|
||||||
|
\return QDateTime object initialized with timeSpec() and utcOffset().
|
||||||
|
\sa timeSpec(), utcOffset(), QwtDate::toDateTime()
|
||||||
|
*/
|
||||||
|
QDateTime QwtDateScaleDraw::toDateTime( double value ) const
|
||||||
|
{
|
||||||
|
QDateTime dt = QwtDate::toDateTime( value, d_data->timeSpec );
|
||||||
|
if ( d_data->timeSpec == Qt::OffsetFromUTC )
|
||||||
|
{
|
||||||
|
dt = dt.addSecs( d_data->utcOffset );
|
||||||
|
dt.setUtcOffset( d_data->utcOffset );
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _QWT_DATE_SCALE_DRAW_H_
|
||||||
|
#define _QWT_DATE_SCALE_DRAW_H_ 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_scale_draw.h"
|
||||||
|
#include "qwt_date.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A class for drawing datetime scales
|
||||||
|
|
||||||
|
QwtDateScaleDraw displays values as datetime labels.
|
||||||
|
The format of the labels depends on the alignment of
|
||||||
|
the major tick labels.
|
||||||
|
|
||||||
|
The default format strings are:
|
||||||
|
|
||||||
|
- Millisecond\n
|
||||||
|
"hh:mm:ss:zzz\nddd dd MMM yyyy"
|
||||||
|
- Second\n
|
||||||
|
"hh:mm:ss\nddd dd MMM yyyy"
|
||||||
|
- Minute\n
|
||||||
|
"hh:mm\nddd dd MMM yyyy"
|
||||||
|
- Hour\n
|
||||||
|
"hh:mm\nddd dd MMM yyyy"
|
||||||
|
- Day\n
|
||||||
|
"ddd dd MMM yyyy"
|
||||||
|
- Week\n
|
||||||
|
"Www yyyy"
|
||||||
|
- Month\n
|
||||||
|
"MMM yyyy"
|
||||||
|
- Year\n
|
||||||
|
"yyyy"
|
||||||
|
|
||||||
|
The format strings can be modified using setDateFormat()
|
||||||
|
or individually for each tick label by overloading dateFormatOfDate(),
|
||||||
|
|
||||||
|
Usually QwtDateScaleDraw is used in combination with
|
||||||
|
QwtDateScaleEngine, that calculates scales for datetime
|
||||||
|
intervals.
|
||||||
|
|
||||||
|
\sa QwtDateScaleEngine, QwtPlot::setAxisScaleDraw()
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtDateScaleDraw: public QwtScaleDraw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtDateScaleDraw( Qt::TimeSpec = Qt::LocalTime );
|
||||||
|
virtual ~QwtDateScaleDraw();
|
||||||
|
|
||||||
|
void setDateFormat( QwtDate::IntervalType, const QString & );
|
||||||
|
QString dateFormat( QwtDate::IntervalType ) const;
|
||||||
|
|
||||||
|
void setTimeSpec( Qt::TimeSpec );
|
||||||
|
Qt::TimeSpec timeSpec() const;
|
||||||
|
|
||||||
|
void setUtcOffset( int seconds );
|
||||||
|
int utcOffset() const;
|
||||||
|
|
||||||
|
void setWeek0Type( QwtDate::Week0Type );
|
||||||
|
QwtDate::Week0Type week0Type() const;
|
||||||
|
|
||||||
|
virtual QwtText label( double ) const;
|
||||||
|
|
||||||
|
QDateTime toDateTime( double ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QwtDate::IntervalType
|
||||||
|
intervalType( const QwtScaleDiv & ) const;
|
||||||
|
|
||||||
|
virtual QString dateFormatOfDate( const QDateTime &,
|
||||||
|
QwtDate::IntervalType ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _QWT_DATE_SCALE_ENGINE_H_
|
||||||
|
#define _QWT_DATE_SCALE_ENGINE_H_ 1
|
||||||
|
|
||||||
|
#include "qwt_date.h"
|
||||||
|
#include "qwt_scale_engine.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A scale engine for date/time values
|
||||||
|
|
||||||
|
QwtDateScaleEngine builds scales from a time intervals.
|
||||||
|
Together with QwtDateScaleDraw it can be used for
|
||||||
|
axes according to date/time values.
|
||||||
|
|
||||||
|
Years, months, weeks, days, hours and minutes are organized
|
||||||
|
in steps with non constant intervals. QwtDateScaleEngine
|
||||||
|
classifies intervals and aligns the boundaries and tick positions
|
||||||
|
according to this classification.
|
||||||
|
|
||||||
|
QwtDateScaleEngine supports representations depending
|
||||||
|
on Qt::TimeSpec specifications. The valid range for scales
|
||||||
|
is limited by the range of QDateTime, that differs
|
||||||
|
between Qt4 and Qt5.
|
||||||
|
|
||||||
|
Datetime values are expected as the number of milliseconds since
|
||||||
|
1970-01-01T00:00:00 Universal Coordinated Time - also known
|
||||||
|
as "The Epoch", that can be converted to QDateTime using
|
||||||
|
QwtDate::toDateTime().
|
||||||
|
|
||||||
|
\sa QwtDate, QwtPlot::setAxisScaleEngine(),
|
||||||
|
QwtAbstractScale::setScaleEngine()
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtDateScaleEngine: public QwtLinearScaleEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtDateScaleEngine( Qt::TimeSpec = Qt::LocalTime );
|
||||||
|
virtual ~QwtDateScaleEngine();
|
||||||
|
|
||||||
|
void setTimeSpec( Qt::TimeSpec );
|
||||||
|
Qt::TimeSpec timeSpec() const;
|
||||||
|
|
||||||
|
void setUtcOffset( int seconds );
|
||||||
|
int utcOffset() const;
|
||||||
|
|
||||||
|
void setWeek0Type( QwtDate::Week0Type );
|
||||||
|
QwtDate::Week0Type week0Type() const;
|
||||||
|
|
||||||
|
void setMaxWeeks( int );
|
||||||
|
int maxWeeks() const;
|
||||||
|
|
||||||
|
virtual void autoScale( int maxNumSteps,
|
||||||
|
double &x1, double &x2, double &stepSize ) const;
|
||||||
|
|
||||||
|
virtual QwtScaleDiv divideScale(
|
||||||
|
double x1, double x2,
|
||||||
|
int maxMajorSteps, int maxMinorSteps,
|
||||||
|
double stepSize = 0.0 ) const;
|
||||||
|
|
||||||
|
virtual QwtDate::IntervalType intervalType(
|
||||||
|
const QDateTime &, const QDateTime &, int maxSteps ) const;
|
||||||
|
|
||||||
|
QDateTime toDateTime( double ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QDateTime alignDate( const QDateTime &, double stepSize,
|
||||||
|
QwtDate::IntervalType, bool up ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QwtScaleDiv buildScaleDiv( const QDateTime &, const QDateTime &,
|
||||||
|
int maxMajorSteps, int maxMinorSteps,
|
||||||
|
QwtDate::IntervalType ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,871 @@
|
|||||||
|
/* -*- 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 "qwt_dial.h"
|
||||||
|
#include "qwt_dial_needle.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_scale_engine.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include "qwt_round_scale_draw.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
#include <qpixmap.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qalgorithms.h>
|
||||||
|
#include <qmath.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
#include <qstyleoption.h>
|
||||||
|
#include <qapplication.h>
|
||||||
|
|
||||||
|
static inline double qwtAngleDist( double a1, double a2 )
|
||||||
|
{
|
||||||
|
double dist = qAbs( a2 - a1 );
|
||||||
|
if ( dist > 360.0 )
|
||||||
|
dist -= 360.0;
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool qwtIsOnArc( double angle, double min, double max )
|
||||||
|
{
|
||||||
|
if ( min < max )
|
||||||
|
{
|
||||||
|
return ( angle >= min ) && ( angle <= max );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ( angle >= min ) || ( angle <= max );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double qwtBoundedAngle( double min, double angle, double max )
|
||||||
|
{
|
||||||
|
double from = qwtNormalizeDegrees( min );
|
||||||
|
double to = qwtNormalizeDegrees( max );
|
||||||
|
|
||||||
|
double a;
|
||||||
|
|
||||||
|
if ( qwtIsOnArc( angle, from, to ) )
|
||||||
|
{
|
||||||
|
a = angle;
|
||||||
|
if ( a < min )
|
||||||
|
a += 360.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( qwtAngleDist( angle, from ) <
|
||||||
|
qwtAngleDist( angle, to ) )
|
||||||
|
{
|
||||||
|
a = min;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtDial::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
frameShadow( Sunken ),
|
||||||
|
lineWidth( 0 ),
|
||||||
|
mode( RotateNeedle ),
|
||||||
|
origin( 90.0 ),
|
||||||
|
minScaleArc( 0.0 ),
|
||||||
|
maxScaleArc( 0.0 ),
|
||||||
|
needle( NULL ),
|
||||||
|
arcOffset( 0.0 ),
|
||||||
|
mouseOffset( 0.0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PrivateData()
|
||||||
|
{
|
||||||
|
delete needle;
|
||||||
|
}
|
||||||
|
Shadow frameShadow;
|
||||||
|
int lineWidth;
|
||||||
|
|
||||||
|
QwtDial::Mode mode;
|
||||||
|
|
||||||
|
double origin;
|
||||||
|
double minScaleArc;
|
||||||
|
double maxScaleArc;
|
||||||
|
|
||||||
|
QwtDialNeedle *needle;
|
||||||
|
|
||||||
|
double arcOffset;
|
||||||
|
double mouseOffset;
|
||||||
|
|
||||||
|
QPixmap pixmapCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
\param parent Parent widget
|
||||||
|
|
||||||
|
Create a dial widget with no needle. The scale is initialized
|
||||||
|
to [ 0.0, 360.0 ] and 360 steps ( QwtAbstractSlider::setTotalSteps() ).
|
||||||
|
The origin of the scale is at 90°,
|
||||||
|
|
||||||
|
The value is set to 0.0.
|
||||||
|
|
||||||
|
The default mode is QwtDial::RotateNeedle.
|
||||||
|
*/
|
||||||
|
QwtDial::QwtDial( QWidget* parent ):
|
||||||
|
QwtAbstractSlider( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
|
||||||
|
setFocusPolicy( Qt::TabFocus );
|
||||||
|
|
||||||
|
QPalette p = palette();
|
||||||
|
for ( int i = 0; i < QPalette::NColorGroups; i++ )
|
||||||
|
{
|
||||||
|
const QPalette::ColorGroup colorGroup =
|
||||||
|
static_cast<QPalette::ColorGroup>( i );
|
||||||
|
|
||||||
|
// Base: background color of the circle inside the frame.
|
||||||
|
// WindowText: background color of the circle inside the scale
|
||||||
|
|
||||||
|
p.setColor( colorGroup, QPalette::WindowText,
|
||||||
|
p.color( colorGroup, QPalette::Base ) );
|
||||||
|
}
|
||||||
|
setPalette( p );
|
||||||
|
|
||||||
|
QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
|
||||||
|
scaleDraw->setRadius( 0 );
|
||||||
|
|
||||||
|
setScaleDraw( scaleDraw );
|
||||||
|
|
||||||
|
setScaleArc( 0.0, 360.0 ); // scale as a full circle
|
||||||
|
|
||||||
|
setScaleMaxMajor( 10 );
|
||||||
|
setScaleMaxMinor( 5 );
|
||||||
|
|
||||||
|
setValue( 0.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtDial::~QwtDial()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the frame shadow value from the frame style.
|
||||||
|
|
||||||
|
\param shadow Frame shadow
|
||||||
|
\sa setLineWidth(), QFrame::setFrameShadow()
|
||||||
|
*/
|
||||||
|
void QwtDial::setFrameShadow( Shadow shadow )
|
||||||
|
{
|
||||||
|
if ( shadow != d_data->frameShadow )
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
d_data->frameShadow = shadow;
|
||||||
|
if ( lineWidth() > 0 )
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Frame shadow
|
||||||
|
/sa setFrameShadow(), lineWidth(), QFrame::frameShadow()
|
||||||
|
*/
|
||||||
|
QwtDial::Shadow QwtDial::frameShadow() const
|
||||||
|
{
|
||||||
|
return d_data->frameShadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the line width of the frame
|
||||||
|
|
||||||
|
\param lineWidth Line width
|
||||||
|
\sa setFrameShadow()
|
||||||
|
*/
|
||||||
|
void QwtDial::setLineWidth( int lineWidth )
|
||||||
|
{
|
||||||
|
if ( lineWidth < 0 )
|
||||||
|
lineWidth = 0;
|
||||||
|
|
||||||
|
if ( d_data->lineWidth != lineWidth )
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
d_data->lineWidth = lineWidth;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Line width of the frame
|
||||||
|
\sa setLineWidth(), frameShadow(), lineWidth()
|
||||||
|
*/
|
||||||
|
int QwtDial::lineWidth() const
|
||||||
|
{
|
||||||
|
return d_data->lineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return bounding rectangle of the circle inside the frame
|
||||||
|
\sa setLineWidth(), scaleInnerRect(), boundingRect()
|
||||||
|
*/
|
||||||
|
QRect QwtDial::innerRect() const
|
||||||
|
{
|
||||||
|
const int lw = lineWidth();
|
||||||
|
return boundingRect().adjusted( lw, lw, -lw, -lw );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return bounding rectangle of the dial including the frame
|
||||||
|
\sa setLineWidth(), scaleInnerRect(), innerRect()
|
||||||
|
*/
|
||||||
|
QRect QwtDial::boundingRect() const
|
||||||
|
{
|
||||||
|
const QRect cr = contentsRect();
|
||||||
|
|
||||||
|
const int dim = qMin( cr.width(), cr.height() );
|
||||||
|
|
||||||
|
QRect inner( 0, 0, dim, dim );
|
||||||
|
inner.moveCenter( cr.center() );
|
||||||
|
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return rectangle inside the scale
|
||||||
|
\sa setLineWidth(), boundingRect(), innerRect()
|
||||||
|
*/
|
||||||
|
QRect QwtDial::scaleInnerRect() const
|
||||||
|
{
|
||||||
|
QRect rect = innerRect();
|
||||||
|
|
||||||
|
const QwtAbstractScaleDraw *sd = scaleDraw();
|
||||||
|
if ( sd )
|
||||||
|
{
|
||||||
|
int scaleDist = qCeil( sd->extent( font() ) );
|
||||||
|
scaleDist++; // margin
|
||||||
|
|
||||||
|
rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the mode of the dial.
|
||||||
|
\param mode New mode
|
||||||
|
|
||||||
|
In case of QwtDial::RotateNeedle the needle is rotating, in case of
|
||||||
|
QwtDial::RotateScale, the needle points to origin()
|
||||||
|
and the scale is rotating.
|
||||||
|
|
||||||
|
The default mode is QwtDial::RotateNeedle.
|
||||||
|
|
||||||
|
\sa mode(), setValue(), setOrigin()
|
||||||
|
*/
|
||||||
|
void QwtDial::setMode( Mode mode )
|
||||||
|
{
|
||||||
|
if ( mode != d_data->mode )
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
d_data->mode = mode;
|
||||||
|
sliderChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Mode of the dial.
|
||||||
|
\sa setMode(), origin(), setScaleArc(), value()
|
||||||
|
*/
|
||||||
|
QwtDial::Mode QwtDial::mode() const
|
||||||
|
{
|
||||||
|
return d_data->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invalidate the internal caches used to speed up repainting
|
||||||
|
*/
|
||||||
|
void QwtDial::invalidateCache()
|
||||||
|
{
|
||||||
|
d_data->pixmapCache = QPixmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Paint the dial
|
||||||
|
\param event Paint event
|
||||||
|
*/
|
||||||
|
void QwtDial::paintEvent( QPaintEvent *event )
|
||||||
|
{
|
||||||
|
QPainter painter( this );
|
||||||
|
painter.setClipRegion( event->region() );
|
||||||
|
|
||||||
|
QStyleOption opt;
|
||||||
|
opt.init(this);
|
||||||
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||||
|
|
||||||
|
if ( d_data->mode == QwtDial::RotateScale )
|
||||||
|
{
|
||||||
|
painter.save();
|
||||||
|
painter.setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
|
||||||
|
drawContents( &painter );
|
||||||
|
|
||||||
|
painter.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRect r = contentsRect();
|
||||||
|
if ( r.size() != d_data->pixmapCache.size() )
|
||||||
|
{
|
||||||
|
d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
|
||||||
|
d_data->pixmapCache.fill( Qt::transparent );
|
||||||
|
|
||||||
|
QPainter p( &d_data->pixmapCache );
|
||||||
|
p.setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
p.translate( -r.topLeft() );
|
||||||
|
|
||||||
|
if ( d_data->mode != QwtDial::RotateScale )
|
||||||
|
drawContents( &p );
|
||||||
|
|
||||||
|
if ( lineWidth() > 0 )
|
||||||
|
drawFrame( &p );
|
||||||
|
|
||||||
|
if ( d_data->mode != QwtDial::RotateNeedle )
|
||||||
|
drawNeedle( &p );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.drawPixmap( r.topLeft(), d_data->pixmapCache );
|
||||||
|
|
||||||
|
if ( d_data->mode == QwtDial::RotateNeedle )
|
||||||
|
drawNeedle( &painter );
|
||||||
|
|
||||||
|
if ( hasFocus() )
|
||||||
|
drawFocusIndicator( &painter );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the focus indicator
|
||||||
|
\param painter Painter
|
||||||
|
*/
|
||||||
|
void QwtDial::drawFocusIndicator( QPainter *painter ) const
|
||||||
|
{
|
||||||
|
QwtPainter::drawFocusRect( painter, this, boundingRect() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the frame around the dial
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\sa lineWidth(), frameShadow()
|
||||||
|
*/
|
||||||
|
void QwtDial::drawFrame( QPainter *painter )
|
||||||
|
{
|
||||||
|
QwtPainter::drawRoundFrame( painter, boundingRect(),
|
||||||
|
palette(), lineWidth(), d_data->frameShadow );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the contents inside the frame
|
||||||
|
|
||||||
|
QPalette::Window is the background color outside of the frame.
|
||||||
|
QPalette::Base is the background color inside the frame.
|
||||||
|
QPalette::WindowText is the background color inside the scale.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
|
||||||
|
\sa boundingRect(), innerRect(),
|
||||||
|
scaleInnerRect(), QWidget::setPalette()
|
||||||
|
*/
|
||||||
|
void QwtDial::drawContents( QPainter *painter ) const
|
||||||
|
{
|
||||||
|
if ( testAttribute( Qt::WA_NoSystemBackground ) ||
|
||||||
|
palette().brush( QPalette::Base ) !=
|
||||||
|
palette().brush( QPalette::Window ) )
|
||||||
|
{
|
||||||
|
const QRectF br = boundingRect();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( palette().brush( QPalette::Base ) );
|
||||||
|
painter->drawEllipse( br );
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRectF insideScaleRect = scaleInnerRect();
|
||||||
|
if ( palette().brush( QPalette::WindowText ) !=
|
||||||
|
palette().brush( QPalette::Base ) )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( palette().brush( QPalette::WindowText ) );
|
||||||
|
painter->drawEllipse( insideScaleRect );
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPointF center = insideScaleRect.center();
|
||||||
|
const double radius = 0.5 * insideScaleRect.width();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
drawScale( painter, center, radius );
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
drawScaleContents( painter, center, radius );
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the needle
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the dial
|
||||||
|
\param radius Length for the needle
|
||||||
|
\param direction Direction of the needle in degrees, counter clockwise
|
||||||
|
\param colorGroup ColorGroup
|
||||||
|
*/
|
||||||
|
void QwtDial::drawNeedle( QPainter *painter, const QPointF ¢er,
|
||||||
|
double radius, double direction, QPalette::ColorGroup colorGroup ) const
|
||||||
|
{
|
||||||
|
if ( d_data->needle )
|
||||||
|
{
|
||||||
|
direction = 360.0 - direction; // counter clockwise
|
||||||
|
d_data->needle->draw( painter, center, radius, direction, colorGroup );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtDial::drawNeedle( QPainter *painter ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QPalette::ColorGroup colorGroup;
|
||||||
|
if ( isEnabled() )
|
||||||
|
colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
|
||||||
|
else
|
||||||
|
colorGroup = QPalette::Disabled;
|
||||||
|
|
||||||
|
const QRectF sr = scaleInnerRect();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
drawNeedle( painter, sr.center(), 0.5 * sr.width(),
|
||||||
|
scaleMap().transform( value() ) + 270.0, colorGroup );
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the scale
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the dial
|
||||||
|
\param radius Radius of the scale
|
||||||
|
*/
|
||||||
|
void QwtDial::drawScale( QPainter *painter,
|
||||||
|
const QPointF ¢er, double radius ) const
|
||||||
|
{
|
||||||
|
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
|
||||||
|
if ( sd == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
sd->setRadius( radius );
|
||||||
|
sd->moveCenter( center );
|
||||||
|
|
||||||
|
QPalette pal = palette();
|
||||||
|
|
||||||
|
const QColor textColor = pal.color( QPalette::Text );
|
||||||
|
pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
|
||||||
|
|
||||||
|
painter->setFont( font() );
|
||||||
|
painter->setPen( QPen( textColor, sd->penWidth() ) );
|
||||||
|
|
||||||
|
painter->setBrush( Qt::red );
|
||||||
|
sd->draw( painter, pal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the contents inside the scale
|
||||||
|
|
||||||
|
Paints nothing.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param center Center of the contents circle
|
||||||
|
\param radius Radius of the contents circle
|
||||||
|
*/
|
||||||
|
void QwtDial::drawScaleContents( QPainter *painter,
|
||||||
|
const QPointF ¢er, double radius ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(painter);
|
||||||
|
Q_UNUSED(center);
|
||||||
|
Q_UNUSED(radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set a needle for the dial
|
||||||
|
|
||||||
|
\param needle Needle
|
||||||
|
|
||||||
|
\warning The needle will be deleted, when a different needle is
|
||||||
|
set or in ~QwtDial()
|
||||||
|
*/
|
||||||
|
void QwtDial::setNeedle( QwtDialNeedle *needle )
|
||||||
|
{
|
||||||
|
if ( needle != d_data->needle )
|
||||||
|
{
|
||||||
|
if ( d_data->needle )
|
||||||
|
delete d_data->needle;
|
||||||
|
|
||||||
|
d_data->needle = needle;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return needle
|
||||||
|
\sa setNeedle()
|
||||||
|
*/
|
||||||
|
const QwtDialNeedle *QwtDial::needle() const
|
||||||
|
{
|
||||||
|
return d_data->needle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return needle
|
||||||
|
\sa setNeedle()
|
||||||
|
*/
|
||||||
|
QwtDialNeedle *QwtDial::needle()
|
||||||
|
{
|
||||||
|
return d_data->needle;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return the scale draw
|
||||||
|
QwtRoundScaleDraw *QwtDial::scaleDraw()
|
||||||
|
{
|
||||||
|
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return the scale draw
|
||||||
|
const QwtRoundScaleDraw *QwtDial::scaleDraw() const
|
||||||
|
{
|
||||||
|
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set an individual scale draw
|
||||||
|
|
||||||
|
The motivation for setting a scale draw is often
|
||||||
|
to overload QwtRoundScaleDraw::label() to return
|
||||||
|
individual tick labels.
|
||||||
|
|
||||||
|
\param scaleDraw Scale draw
|
||||||
|
\warning The previous scale draw is deleted
|
||||||
|
*/
|
||||||
|
void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
|
||||||
|
{
|
||||||
|
setAbstractScaleDraw( scaleDraw );
|
||||||
|
sliderChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the arc of the scale
|
||||||
|
|
||||||
|
\param minArc Lower limit
|
||||||
|
\param maxArc Upper limit
|
||||||
|
|
||||||
|
\sa minScaleArc(), maxScaleArc()
|
||||||
|
*/
|
||||||
|
void QwtDial::setScaleArc( double minArc, double maxArc )
|
||||||
|
{
|
||||||
|
if ( minArc != 360.0 && minArc != -360.0 )
|
||||||
|
minArc = ::fmod( minArc, 360.0 );
|
||||||
|
if ( maxArc != 360.0 && maxArc != -360.0 )
|
||||||
|
maxArc = ::fmod( maxArc, 360.0 );
|
||||||
|
|
||||||
|
double minScaleArc = qMin( minArc, maxArc );
|
||||||
|
double maxScaleArc = qMax( minArc, maxArc );
|
||||||
|
|
||||||
|
if ( maxScaleArc - minScaleArc > 360.0 )
|
||||||
|
maxScaleArc = minScaleArc + 360.0;
|
||||||
|
|
||||||
|
if ( ( minScaleArc != d_data->minScaleArc ) ||
|
||||||
|
( maxScaleArc != d_data->maxScaleArc ) )
|
||||||
|
{
|
||||||
|
d_data->minScaleArc = minScaleArc;
|
||||||
|
d_data->maxScaleArc = maxScaleArc;
|
||||||
|
|
||||||
|
invalidateCache();
|
||||||
|
sliderChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the lower limit for the scale arc
|
||||||
|
|
||||||
|
\param min Lower limit of the scale arc
|
||||||
|
\sa setScaleArc(), setMaxScaleArc()
|
||||||
|
*/
|
||||||
|
void QwtDial::setMinScaleArc( double min )
|
||||||
|
{
|
||||||
|
setScaleArc( min, d_data->maxScaleArc );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Lower limit of the scale arc
|
||||||
|
\sa setScaleArc()
|
||||||
|
*/
|
||||||
|
double QwtDial::minScaleArc() const
|
||||||
|
{
|
||||||
|
return d_data->minScaleArc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the upper limit for the scale arc
|
||||||
|
|
||||||
|
\param max Upper limit of the scale arc
|
||||||
|
\sa setScaleArc(), setMinScaleArc()
|
||||||
|
*/
|
||||||
|
void QwtDial::setMaxScaleArc( double max )
|
||||||
|
{
|
||||||
|
setScaleArc( d_data->minScaleArc, max );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Upper limit of the scale arc
|
||||||
|
\sa setScaleArc()
|
||||||
|
*/
|
||||||
|
double QwtDial::maxScaleArc() const
|
||||||
|
{
|
||||||
|
return d_data->maxScaleArc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the origin
|
||||||
|
|
||||||
|
The origin is the angle where scale and needle is relative to.
|
||||||
|
|
||||||
|
\param origin New origin
|
||||||
|
\sa origin()
|
||||||
|
*/
|
||||||
|
void QwtDial::setOrigin( double origin )
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
d_data->origin = origin;
|
||||||
|
sliderChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The origin is the angle where scale and needle is relative to.
|
||||||
|
|
||||||
|
\return Origin of the dial
|
||||||
|
\sa setOrigin()
|
||||||
|
*/
|
||||||
|
double QwtDial::origin() const
|
||||||
|
{
|
||||||
|
return d_data->origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Size hint
|
||||||
|
\sa minimumSizeHint()
|
||||||
|
*/
|
||||||
|
QSize QwtDial::sizeHint() const
|
||||||
|
{
|
||||||
|
int sh = 0;
|
||||||
|
if ( scaleDraw() )
|
||||||
|
sh = qCeil( scaleDraw()->extent( font() ) );
|
||||||
|
|
||||||
|
const int d = 6 * sh + 2 * lineWidth();
|
||||||
|
|
||||||
|
QSize hint( d, d );
|
||||||
|
if ( !isReadOnly() )
|
||||||
|
hint = hint.expandedTo( QApplication::globalStrut() );
|
||||||
|
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Minimum size hint
|
||||||
|
\sa sizeHint()
|
||||||
|
*/
|
||||||
|
QSize QwtDial::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
int sh = 0;
|
||||||
|
if ( scaleDraw() )
|
||||||
|
sh = qCeil( scaleDraw()->extent( font() ) );
|
||||||
|
|
||||||
|
const int d = 3 * sh + 2 * lineWidth();
|
||||||
|
|
||||||
|
return QSize( d, d );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine what to do when the user presses a mouse button.
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\retval True, when the inner circle contains pos
|
||||||
|
\sa scrolledTo()
|
||||||
|
*/
|
||||||
|
bool QwtDial::isScrollPosition( const QPoint &pos ) const
|
||||||
|
{
|
||||||
|
const QRegion region( innerRect(), QRegion::Ellipse );
|
||||||
|
if ( region.contains( pos ) && ( pos != innerRect().center() ) )
|
||||||
|
{
|
||||||
|
double angle = QLineF( rect().center(), pos ).angle();
|
||||||
|
if ( d_data->mode == QwtDial::RotateScale )
|
||||||
|
angle = 360.0 - angle;
|
||||||
|
|
||||||
|
double valueAngle =
|
||||||
|
qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
|
||||||
|
|
||||||
|
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
|
||||||
|
d_data->arcOffset = scaleMap().p1();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine the value for a new position of the
|
||||||
|
slider handle.
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\return Value for the mouse position
|
||||||
|
\sa isScrollPosition()
|
||||||
|
*/
|
||||||
|
double QwtDial::scrolledTo( const QPoint &pos ) const
|
||||||
|
{
|
||||||
|
double angle = QLineF( rect().center(), pos ).angle();
|
||||||
|
if ( d_data->mode == QwtDial::RotateScale )
|
||||||
|
{
|
||||||
|
angle += scaleMap().p1() - d_data->arcOffset;
|
||||||
|
angle = 360.0 - angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
|
||||||
|
angle = qwtNormalizeDegrees( 90.0 - angle );
|
||||||
|
|
||||||
|
if ( scaleMap().pDist() >= 360.0 )
|
||||||
|
{
|
||||||
|
if ( angle < scaleMap().p1() )
|
||||||
|
angle += 360.0;
|
||||||
|
|
||||||
|
if ( !wrapping() )
|
||||||
|
{
|
||||||
|
double boundedAngle = angle;
|
||||||
|
|
||||||
|
const double arc = angle - scaleMap().transform( value() );
|
||||||
|
if ( qAbs( arc ) > 180.0 )
|
||||||
|
{
|
||||||
|
boundedAngle = ( arc > 0 )
|
||||||
|
? scaleMap().p1() : scaleMap().p2();
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->mouseOffset += ( boundedAngle - angle );
|
||||||
|
|
||||||
|
angle = boundedAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double boundedAngle =
|
||||||
|
qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
|
||||||
|
|
||||||
|
if ( !wrapping() )
|
||||||
|
d_data->mouseOffset += ( boundedAngle - angle );
|
||||||
|
|
||||||
|
angle = boundedAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scaleMap().invTransform( angle );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change Event handler
|
||||||
|
\param event Change event
|
||||||
|
|
||||||
|
Invalidates internal paint caches if necessary
|
||||||
|
*/
|
||||||
|
void QwtDial::changeEvent( QEvent *event )
|
||||||
|
{
|
||||||
|
switch( event->type() )
|
||||||
|
{
|
||||||
|
case QEvent::EnabledChange:
|
||||||
|
case QEvent::FontChange:
|
||||||
|
case QEvent::StyleChange:
|
||||||
|
case QEvent::PaletteChange:
|
||||||
|
case QEvent::LanguageChange:
|
||||||
|
case QEvent::LocaleChange:
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtAbstractSlider::changeEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Wheel Event handler
|
||||||
|
\param event Wheel event
|
||||||
|
*/
|
||||||
|
void QwtDial::wheelEvent( QWheelEvent *event )
|
||||||
|
{
|
||||||
|
const QRegion region( innerRect(), QRegion::Ellipse );
|
||||||
|
if ( region.contains( event->pos() ) )
|
||||||
|
QwtAbstractSlider::wheelEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtDial::setAngleRange( double angle, double span )
|
||||||
|
{
|
||||||
|
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
|
||||||
|
if ( sd )
|
||||||
|
{
|
||||||
|
angle = qwtNormalizeDegrees( angle - 270.0 );
|
||||||
|
sd->setAngleRange( angle, angle + span );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invalidate the internal caches and call
|
||||||
|
QwtAbstractSlider::scaleChange()
|
||||||
|
*/
|
||||||
|
void QwtDial::scaleChange()
|
||||||
|
{
|
||||||
|
invalidateCache();
|
||||||
|
QwtAbstractSlider::scaleChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtDial::sliderChange()
|
||||||
|
{
|
||||||
|
setAngleRange( d_data->origin + d_data->minScaleArc,
|
||||||
|
d_data->maxScaleArc - d_data->minScaleArc );
|
||||||
|
|
||||||
|
if ( mode() == RotateScale )
|
||||||
|
{
|
||||||
|
const double arc = scaleMap().transform( value() ) - scaleMap().p1();
|
||||||
|
setAngleRange( d_data->origin - arc,
|
||||||
|
d_data->maxScaleArc - d_data->minScaleArc );
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtAbstractSlider::sliderChange();
|
||||||
|
}
|
||||||
@ -0,0 +1,168 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_DIAL_H
|
||||||
|
#define QWT_DIAL_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_abstract_slider.h"
|
||||||
|
#include "qwt_abstract_scale_draw.h"
|
||||||
|
#include <qframe.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
|
||||||
|
class QwtDialNeedle;
|
||||||
|
class QwtRoundScaleDraw;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief QwtDial class provides a rounded range control.
|
||||||
|
|
||||||
|
QwtDial is intended as base class for dial widgets like
|
||||||
|
speedometers, compass widgets, clocks ...
|
||||||
|
|
||||||
|
\image html dials2.png
|
||||||
|
|
||||||
|
A dial contains a scale and a needle indicating the current value
|
||||||
|
of the dial. Depending on Mode one of them is fixed and the
|
||||||
|
other is rotating. If not isReadOnly() the
|
||||||
|
dial can be rotated by dragging the mouse or using keyboard inputs
|
||||||
|
(see QwtAbstractSlider::keyPressEvent()). A dial might be wrapping, what means
|
||||||
|
a rotation below/above one limit continues on the other limit (f.e compass).
|
||||||
|
The scale might cover any arc of the dial, its values are related to
|
||||||
|
the origin() of the dial.
|
||||||
|
|
||||||
|
Often dials have to be updated very often according to values from external
|
||||||
|
devices. For these high refresh rates QwtDial caches as much as possible.
|
||||||
|
For derived classes it might be necessary to clear these caches manually
|
||||||
|
according to attribute changes using invalidateCache().
|
||||||
|
|
||||||
|
\sa QwtCompass, QwtAnalogClock, QwtDialNeedle
|
||||||
|
\note The controls and dials examples shows different types of dials.
|
||||||
|
\note QDial is more similar to QwtKnob than to QwtDial
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtDial: public QwtAbstractSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_ENUMS( Shadow Mode Direction )
|
||||||
|
|
||||||
|
Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth )
|
||||||
|
Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
|
||||||
|
Q_PROPERTY( Mode mode READ mode WRITE setMode )
|
||||||
|
Q_PROPERTY( double origin READ origin WRITE setOrigin )
|
||||||
|
Q_PROPERTY( double minScaleArc READ minScaleArc WRITE setMinScaleArc )
|
||||||
|
Q_PROPERTY( double maxScaleArc READ maxScaleArc WRITE setMaxScaleArc )
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Frame shadow
|
||||||
|
|
||||||
|
Unfortunately it is not possible to use QFrame::Shadow
|
||||||
|
as a property of a widget that is not derived from QFrame.
|
||||||
|
The following enum is made for the designer only. It is safe
|
||||||
|
to use QFrame::Shadow instead.
|
||||||
|
*/
|
||||||
|
enum Shadow
|
||||||
|
{
|
||||||
|
//! QFrame::Plain
|
||||||
|
Plain = QFrame::Plain,
|
||||||
|
|
||||||
|
//! QFrame::Raised
|
||||||
|
Raised = QFrame::Raised,
|
||||||
|
|
||||||
|
//! QFrame::Sunken
|
||||||
|
Sunken = QFrame::Sunken
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Mode controlling whether the needle or the scale is rotating
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
//! The needle is rotating
|
||||||
|
RotateNeedle,
|
||||||
|
|
||||||
|
//! The needle is fixed, the scales are rotating
|
||||||
|
RotateScale
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit QwtDial( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtDial();
|
||||||
|
|
||||||
|
void setFrameShadow( Shadow );
|
||||||
|
Shadow frameShadow() const;
|
||||||
|
|
||||||
|
void setLineWidth( int );
|
||||||
|
int lineWidth() const;
|
||||||
|
|
||||||
|
void setMode( Mode );
|
||||||
|
Mode mode() const;
|
||||||
|
|
||||||
|
void setScaleArc( double minArc, double maxArc );
|
||||||
|
|
||||||
|
void setMinScaleArc( double );
|
||||||
|
double minScaleArc() const;
|
||||||
|
|
||||||
|
void setMaxScaleArc( double );
|
||||||
|
double maxScaleArc() const;
|
||||||
|
|
||||||
|
virtual void setOrigin( double );
|
||||||
|
double origin() const;
|
||||||
|
|
||||||
|
void setNeedle( QwtDialNeedle * );
|
||||||
|
const QwtDialNeedle *needle() const;
|
||||||
|
QwtDialNeedle *needle();
|
||||||
|
|
||||||
|
QRect boundingRect() const;
|
||||||
|
QRect innerRect() const;
|
||||||
|
|
||||||
|
virtual QRect scaleInnerRect() const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
virtual QSize minimumSizeHint() const;
|
||||||
|
|
||||||
|
void setScaleDraw( QwtRoundScaleDraw * );
|
||||||
|
|
||||||
|
QwtRoundScaleDraw *scaleDraw();
|
||||||
|
const QwtRoundScaleDraw *scaleDraw() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void wheelEvent( QWheelEvent * );
|
||||||
|
virtual void paintEvent( QPaintEvent * );
|
||||||
|
virtual void changeEvent( QEvent * );
|
||||||
|
|
||||||
|
virtual void drawFrame( QPainter * );
|
||||||
|
virtual void drawContents( QPainter * ) const;
|
||||||
|
virtual void drawFocusIndicator( QPainter * ) const;
|
||||||
|
|
||||||
|
void invalidateCache();
|
||||||
|
|
||||||
|
virtual void drawScale( QPainter *,
|
||||||
|
const QPointF ¢er, double radius ) const;
|
||||||
|
|
||||||
|
virtual void drawScaleContents( QPainter *painter,
|
||||||
|
const QPointF ¢er, double radius ) const;
|
||||||
|
|
||||||
|
virtual void drawNeedle( QPainter *, const QPointF &,
|
||||||
|
double radius, double direction, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
virtual double scrolledTo( const QPoint & ) const;
|
||||||
|
virtual bool isScrollPosition( const QPoint & ) const;
|
||||||
|
|
||||||
|
virtual void sliderChange();
|
||||||
|
virtual void scaleChange();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setAngleRange( double angle, double span );
|
||||||
|
void drawNeedle( QPainter * ) const;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_DIAL_NEEDLE_H
|
||||||
|
#define QWT_DIAL_NEEDLE_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpalette.h>
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
class QPoint;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Base class for needles that can be used in a QwtDial.
|
||||||
|
|
||||||
|
QwtDialNeedle is a pointer that indicates a value by pointing
|
||||||
|
to a specific direction.
|
||||||
|
|
||||||
|
\sa QwtDial, QwtCompass
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtDialNeedle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QwtDialNeedle();
|
||||||
|
virtual ~QwtDialNeedle();
|
||||||
|
|
||||||
|
virtual void setPalette( const QPalette & );
|
||||||
|
const QPalette &palette() const;
|
||||||
|
|
||||||
|
virtual void draw( QPainter *painter, const QPointF ¢er,
|
||||||
|
double length, double direction,
|
||||||
|
QPalette::ColorGroup = QPalette::Active ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
\brief Draw the needle
|
||||||
|
|
||||||
|
The origin of the needle is at position (0.0, 0.0 )
|
||||||
|
pointing in direction 0.0 ( = east ).
|
||||||
|
|
||||||
|
The painter is already initialized with translation and
|
||||||
|
rotation.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param length Length of the needle
|
||||||
|
\param colorGroup Color group, used for painting
|
||||||
|
|
||||||
|
\sa setPalette(), palette()
|
||||||
|
*/
|
||||||
|
virtual void drawNeedle( QPainter *painter,
|
||||||
|
double length, QPalette::ColorGroup colorGroup ) const = 0;
|
||||||
|
|
||||||
|
virtual void drawKnob( QPainter *, double width,
|
||||||
|
const QBrush &, bool sunken ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPalette d_palette;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A needle for dial widgets
|
||||||
|
|
||||||
|
The following colors are used:
|
||||||
|
|
||||||
|
- QPalette::Mid\n
|
||||||
|
Pointer
|
||||||
|
- QPalette::Base\n
|
||||||
|
Knob
|
||||||
|
|
||||||
|
\sa QwtDial, QwtCompass
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtDialSimpleNeedle: public QwtDialNeedle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Style of the needle
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
//! Arrow
|
||||||
|
Arrow,
|
||||||
|
|
||||||
|
//! A straight line from the center
|
||||||
|
Ray
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtDialSimpleNeedle( Style, bool hasKnob = true,
|
||||||
|
const QColor &mid = Qt::gray, const QColor &base = Qt::darkGray );
|
||||||
|
|
||||||
|
void setWidth( double width );
|
||||||
|
double width() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawNeedle( QPainter *, double length,
|
||||||
|
QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Style d_style;
|
||||||
|
bool d_hasKnob;
|
||||||
|
double d_width;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A magnet needle for compass widgets
|
||||||
|
|
||||||
|
A magnet needle points to two opposite directions indicating
|
||||||
|
north and south.
|
||||||
|
|
||||||
|
The following colors are used:
|
||||||
|
- QPalette::Light\n
|
||||||
|
Used for pointing south
|
||||||
|
- QPalette::Dark\n
|
||||||
|
Used for pointing north
|
||||||
|
- QPalette::Base\n
|
||||||
|
Knob (ThinStyle only)
|
||||||
|
|
||||||
|
\sa QwtDial, QwtCompass
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtCompassMagnetNeedle: public QwtDialNeedle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Style of the needle
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
//! A needle with a triangular shape
|
||||||
|
TriangleStyle,
|
||||||
|
|
||||||
|
//! A thin needle
|
||||||
|
ThinStyle
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtCompassMagnetNeedle( Style = TriangleStyle,
|
||||||
|
const QColor &light = Qt::white, const QColor &dark = Qt::red );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawNeedle( QPainter *,
|
||||||
|
double length, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Style d_style;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief An indicator for the wind direction
|
||||||
|
|
||||||
|
QwtCompassWindArrow shows the direction where the wind comes from.
|
||||||
|
|
||||||
|
- QPalette::Light\n
|
||||||
|
Used for Style1, or the light half of Style2
|
||||||
|
- QPalette::Dark\n
|
||||||
|
Used for the dark half of Style2
|
||||||
|
|
||||||
|
\sa QwtDial, QwtCompass
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtCompassWindArrow: public QwtDialNeedle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Style of the arrow
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
//! A needle pointing to the center
|
||||||
|
Style1,
|
||||||
|
|
||||||
|
//! A needle pointing to the center
|
||||||
|
Style2
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtCompassWindArrow( Style, const QColor &light = Qt::white,
|
||||||
|
const QColor &dark = Qt::gray );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawNeedle( QPainter *,
|
||||||
|
double length, QPalette::ColorGroup ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Style d_style;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,591 @@
|
|||||||
|
/* -*- 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 "qwt_dyngrid_layout.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include <qvector.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
|
||||||
|
class QwtDynGridLayout::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
isDirty( true )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLayoutCache();
|
||||||
|
|
||||||
|
mutable QList<QLayoutItem*> itemList;
|
||||||
|
|
||||||
|
uint maxColumns;
|
||||||
|
uint numRows;
|
||||||
|
uint numColumns;
|
||||||
|
|
||||||
|
Qt::Orientations expanding;
|
||||||
|
|
||||||
|
bool isDirty;
|
||||||
|
QVector<QSize> itemSizeHints;
|
||||||
|
};
|
||||||
|
|
||||||
|
void QwtDynGridLayout::PrivateData::updateLayoutCache()
|
||||||
|
{
|
||||||
|
itemSizeHints.resize( itemList.count() );
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for ( QList<QLayoutItem*>::iterator it = itemList.begin();
|
||||||
|
it != itemList.end(); ++it, index++ )
|
||||||
|
{
|
||||||
|
itemSizeHints[ index ] = ( *it )->sizeHint();
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param parent Parent widget
|
||||||
|
\param margin Margin
|
||||||
|
\param spacing Spacing
|
||||||
|
*/
|
||||||
|
|
||||||
|
QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
|
||||||
|
int margin, int spacing ):
|
||||||
|
QLayout( parent )
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
setSpacing( spacing );
|
||||||
|
setMargin( margin );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param spacing Spacing
|
||||||
|
*/
|
||||||
|
|
||||||
|
QwtDynGridLayout::QwtDynGridLayout( int spacing )
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
setSpacing( spacing );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Initialize the layout with default values.
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::init()
|
||||||
|
{
|
||||||
|
d_data = new QwtDynGridLayout::PrivateData;
|
||||||
|
d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
|
||||||
|
d_data->expanding = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
|
||||||
|
QwtDynGridLayout::~QwtDynGridLayout()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < d_data->itemList.size(); i++ )
|
||||||
|
delete d_data->itemList[i];
|
||||||
|
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Invalidate all internal caches
|
||||||
|
void QwtDynGridLayout::invalidate()
|
||||||
|
{
|
||||||
|
d_data->isDirty = true;
|
||||||
|
QLayout::invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Limit the number of columns.
|
||||||
|
\param maxColumns upper limit, 0 means unlimited
|
||||||
|
\sa maxColumns()
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::setMaxColumns( uint maxColumns )
|
||||||
|
{
|
||||||
|
d_data->maxColumns = maxColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Return the upper limit for the number of columns.
|
||||||
|
|
||||||
|
0 means unlimited, what is the default.
|
||||||
|
|
||||||
|
\return Upper limit for the number of columns
|
||||||
|
\sa setMaxColumns()
|
||||||
|
*/
|
||||||
|
uint QwtDynGridLayout::maxColumns() const
|
||||||
|
{
|
||||||
|
return d_data->maxColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Add an item to the next free position.
|
||||||
|
\param item Layout item
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::addItem( QLayoutItem *item )
|
||||||
|
{
|
||||||
|
d_data->itemList.append( item );
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return true if this layout is empty.
|
||||||
|
*/
|
||||||
|
bool QwtDynGridLayout::isEmpty() const
|
||||||
|
{
|
||||||
|
return d_data->itemList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return number of layout items
|
||||||
|
*/
|
||||||
|
uint QwtDynGridLayout::itemCount() const
|
||||||
|
{
|
||||||
|
return d_data->itemList.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find the item at a specific index
|
||||||
|
|
||||||
|
\param index Index
|
||||||
|
\return Item at a specific index
|
||||||
|
\sa takeAt()
|
||||||
|
*/
|
||||||
|
QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
|
||||||
|
{
|
||||||
|
if ( index < 0 || index >= d_data->itemList.count() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return d_data->itemList.at( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find the item at a specific index and remove it from the layout
|
||||||
|
|
||||||
|
\param index Index
|
||||||
|
\return Layout item, removed from the layout
|
||||||
|
\sa itemAt()
|
||||||
|
*/
|
||||||
|
QLayoutItem *QwtDynGridLayout::takeAt( int index )
|
||||||
|
{
|
||||||
|
if ( index < 0 || index >= d_data->itemList.count() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
d_data->isDirty = true;
|
||||||
|
return d_data->itemList.takeAt( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Number of items in the layout
|
||||||
|
int QwtDynGridLayout::count() const
|
||||||
|
{
|
||||||
|
return d_data->itemList.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set whether this layout can make use of more space than sizeHint().
|
||||||
|
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
|
||||||
|
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
|
||||||
|
to grow in both dimensions. The default value is 0.
|
||||||
|
|
||||||
|
\param expanding Or'd orientations
|
||||||
|
\sa expandingDirections()
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
|
||||||
|
{
|
||||||
|
d_data->expanding = expanding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Returns whether this layout can make use of more space than sizeHint().
|
||||||
|
|
||||||
|
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
|
||||||
|
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
|
||||||
|
to grow in both dimensions.
|
||||||
|
|
||||||
|
\return Orientations, where the layout expands
|
||||||
|
\sa setExpandingDirections()
|
||||||
|
*/
|
||||||
|
Qt::Orientations QwtDynGridLayout::expandingDirections() const
|
||||||
|
{
|
||||||
|
return d_data->expanding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Reorganizes columns and rows and resizes managed items within
|
||||||
|
a rectangle.
|
||||||
|
|
||||||
|
\param rect Layout geometry
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::setGeometry( const QRect &rect )
|
||||||
|
{
|
||||||
|
QLayout::setGeometry( rect );
|
||||||
|
|
||||||
|
if ( isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data->numColumns = columnsForWidth( rect.width() );
|
||||||
|
d_data->numRows = itemCount() / d_data->numColumns;
|
||||||
|
if ( itemCount() % d_data->numColumns )
|
||||||
|
d_data->numRows++;
|
||||||
|
|
||||||
|
QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
|
||||||
|
it != d_data->itemList.end(); ++it )
|
||||||
|
{
|
||||||
|
( *it )->setGeometry( itemGeometries[index] );
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Calculate the number of columns for a given width.
|
||||||
|
|
||||||
|
The calculation tries to use as many columns as possible
|
||||||
|
( limited by maxColumns() )
|
||||||
|
|
||||||
|
\param width Available width for all columns
|
||||||
|
\return Number of columns for a given width
|
||||||
|
|
||||||
|
\sa maxColumns(), setMaxColumns()
|
||||||
|
*/
|
||||||
|
uint QwtDynGridLayout::columnsForWidth( int width ) const
|
||||||
|
{
|
||||||
|
if ( isEmpty() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint maxColumns = itemCount();
|
||||||
|
if ( d_data->maxColumns > 0 )
|
||||||
|
maxColumns = qMin( d_data->maxColumns, maxColumns );
|
||||||
|
|
||||||
|
if ( maxRowWidth( maxColumns ) <= width )
|
||||||
|
return maxColumns;
|
||||||
|
|
||||||
|
for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
|
||||||
|
{
|
||||||
|
const int rowWidth = maxRowWidth( numColumns );
|
||||||
|
if ( rowWidth > width )
|
||||||
|
return numColumns - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; // At least 1 column
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the width of a layout for a given number of
|
||||||
|
columns.
|
||||||
|
|
||||||
|
\param numColumns Given number of columns
|
||||||
|
\param itemWidth Array of the width hints for all items
|
||||||
|
*/
|
||||||
|
int QwtDynGridLayout::maxRowWidth( int numColumns ) const
|
||||||
|
{
|
||||||
|
int col;
|
||||||
|
|
||||||
|
QVector<int> colWidth( numColumns );
|
||||||
|
for ( col = 0; col < numColumns; col++ )
|
||||||
|
colWidth[col] = 0;
|
||||||
|
|
||||||
|
if ( d_data->isDirty )
|
||||||
|
d_data->updateLayoutCache();
|
||||||
|
|
||||||
|
for ( int index = 0;
|
||||||
|
index < d_data->itemSizeHints.count(); index++ )
|
||||||
|
{
|
||||||
|
col = index % numColumns;
|
||||||
|
colWidth[col] = qMax( colWidth[col],
|
||||||
|
d_data->itemSizeHints[int( index )].width() );
|
||||||
|
}
|
||||||
|
|
||||||
|
int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
|
||||||
|
for ( col = 0; col < numColumns; col++ )
|
||||||
|
rowWidth += colWidth[col];
|
||||||
|
|
||||||
|
return rowWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the maximum width of all layout items
|
||||||
|
*/
|
||||||
|
int QwtDynGridLayout::maxItemWidth() const
|
||||||
|
{
|
||||||
|
if ( isEmpty() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ( d_data->isDirty )
|
||||||
|
d_data->updateLayoutCache();
|
||||||
|
|
||||||
|
int w = 0;
|
||||||
|
for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
|
||||||
|
{
|
||||||
|
const int itemW = d_data->itemSizeHints[i].width();
|
||||||
|
if ( itemW > w )
|
||||||
|
w = itemW;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the geometries of the layout items for a layout
|
||||||
|
with numColumns columns and a given rectangle.
|
||||||
|
|
||||||
|
\param rect Rect where to place the items
|
||||||
|
\param numColumns Number of columns
|
||||||
|
\return item geometries
|
||||||
|
*/
|
||||||
|
|
||||||
|
QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
|
||||||
|
uint numColumns ) const
|
||||||
|
{
|
||||||
|
QList<QRect> itemGeometries;
|
||||||
|
if ( numColumns == 0 || isEmpty() )
|
||||||
|
return itemGeometries;
|
||||||
|
|
||||||
|
uint numRows = itemCount() / numColumns;
|
||||||
|
if ( numColumns % itemCount() )
|
||||||
|
numRows++;
|
||||||
|
|
||||||
|
if ( numRows == 0 )
|
||||||
|
return itemGeometries;
|
||||||
|
|
||||||
|
QVector<int> rowHeight( numRows );
|
||||||
|
QVector<int> colWidth( numColumns );
|
||||||
|
|
||||||
|
layoutGrid( numColumns, rowHeight, colWidth );
|
||||||
|
|
||||||
|
bool expandH, expandV;
|
||||||
|
expandH = expandingDirections() & Qt::Horizontal;
|
||||||
|
expandV = expandingDirections() & Qt::Vertical;
|
||||||
|
|
||||||
|
if ( expandH || expandV )
|
||||||
|
stretchGrid( rect, numColumns, rowHeight, colWidth );
|
||||||
|
|
||||||
|
const int maxColumns = d_data->maxColumns;
|
||||||
|
d_data->maxColumns = numColumns;
|
||||||
|
const QRect alignedRect = alignmentRect( rect );
|
||||||
|
d_data->maxColumns = maxColumns;
|
||||||
|
|
||||||
|
const int xOffset = expandH ? 0 : alignedRect.x();
|
||||||
|
const int yOffset = expandV ? 0 : alignedRect.y();
|
||||||
|
|
||||||
|
QVector<int> colX( numColumns );
|
||||||
|
QVector<int> rowY( numRows );
|
||||||
|
|
||||||
|
const int xySpace = spacing();
|
||||||
|
|
||||||
|
rowY[0] = yOffset + margin();
|
||||||
|
for ( uint r = 1; r < numRows; r++ )
|
||||||
|
rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
|
||||||
|
|
||||||
|
colX[0] = xOffset + margin();
|
||||||
|
for ( uint c = 1; c < numColumns; c++ )
|
||||||
|
colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
|
||||||
|
|
||||||
|
const int itemCount = d_data->itemList.size();
|
||||||
|
for ( int i = 0; i < itemCount; i++ )
|
||||||
|
{
|
||||||
|
const int row = i / numColumns;
|
||||||
|
const int col = i % numColumns;
|
||||||
|
|
||||||
|
QRect itemGeometry( colX[col], rowY[row],
|
||||||
|
colWidth[col], rowHeight[row] );
|
||||||
|
itemGeometries.append( itemGeometry );
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemGeometries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the dimensions for the columns and rows for a grid
|
||||||
|
of numColumns columns.
|
||||||
|
|
||||||
|
\param numColumns Number of columns.
|
||||||
|
\param rowHeight Array where to fill in the calculated row heights.
|
||||||
|
\param colWidth Array where to fill in the calculated column widths.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QwtDynGridLayout::layoutGrid( uint numColumns,
|
||||||
|
QVector<int>& rowHeight, QVector<int>& colWidth ) const
|
||||||
|
{
|
||||||
|
if ( numColumns <= 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( d_data->isDirty )
|
||||||
|
d_data->updateLayoutCache();
|
||||||
|
|
||||||
|
for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
|
||||||
|
{
|
||||||
|
const int row = index / numColumns;
|
||||||
|
const int col = index % numColumns;
|
||||||
|
|
||||||
|
const QSize &size = d_data->itemSizeHints[int( index )];
|
||||||
|
|
||||||
|
rowHeight[row] = ( col == 0 )
|
||||||
|
? size.height() : qMax( rowHeight[row], size.height() );
|
||||||
|
colWidth[col] = ( row == 0 )
|
||||||
|
? size.width() : qMax( colWidth[col], size.width() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return true: QwtDynGridLayout implements heightForWidth().
|
||||||
|
\sa heightForWidth()
|
||||||
|
*/
|
||||||
|
bool QwtDynGridLayout::hasHeightForWidth() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The preferred height for this layout, given a width.
|
||||||
|
\sa hasHeightForWidth()
|
||||||
|
*/
|
||||||
|
int QwtDynGridLayout::heightForWidth( int width ) const
|
||||||
|
{
|
||||||
|
if ( isEmpty() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint numColumns = columnsForWidth( width );
|
||||||
|
uint numRows = itemCount() / numColumns;
|
||||||
|
if ( itemCount() % numColumns )
|
||||||
|
numRows++;
|
||||||
|
|
||||||
|
QVector<int> rowHeight( numRows );
|
||||||
|
QVector<int> colWidth( numColumns );
|
||||||
|
|
||||||
|
layoutGrid( numColumns, rowHeight, colWidth );
|
||||||
|
|
||||||
|
int h = 2 * margin() + ( numRows - 1 ) * spacing();
|
||||||
|
for ( uint row = 0; row < numRows; row++ )
|
||||||
|
h += rowHeight[row];
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Stretch columns in case of expanding() & QSizePolicy::Horizontal and
|
||||||
|
rows in case of expanding() & QSizePolicy::Vertical to fill the entire
|
||||||
|
rect. Rows and columns are stretched with the same factor.
|
||||||
|
|
||||||
|
\param rect Bounding rectangle
|
||||||
|
\param numColumns Number of columns
|
||||||
|
\param rowHeight Array to be filled with the calculated row heights
|
||||||
|
\param colWidth Array to be filled with the calculated column widths
|
||||||
|
|
||||||
|
\sa setExpanding(), expanding()
|
||||||
|
*/
|
||||||
|
void QwtDynGridLayout::stretchGrid( const QRect &rect,
|
||||||
|
uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
|
||||||
|
{
|
||||||
|
if ( numColumns == 0 || isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool expandH, expandV;
|
||||||
|
expandH = expandingDirections() & Qt::Horizontal;
|
||||||
|
expandV = expandingDirections() & Qt::Vertical;
|
||||||
|
|
||||||
|
if ( expandH )
|
||||||
|
{
|
||||||
|
int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
|
||||||
|
for ( uint col = 0; col < numColumns; col++ )
|
||||||
|
xDelta -= colWidth[col];
|
||||||
|
|
||||||
|
if ( xDelta > 0 )
|
||||||
|
{
|
||||||
|
for ( uint col = 0; col < numColumns; col++ )
|
||||||
|
{
|
||||||
|
const int space = xDelta / ( numColumns - col );
|
||||||
|
colWidth[col] += space;
|
||||||
|
xDelta -= space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( expandV )
|
||||||
|
{
|
||||||
|
uint numRows = itemCount() / numColumns;
|
||||||
|
if ( itemCount() % numColumns )
|
||||||
|
numRows++;
|
||||||
|
|
||||||
|
int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
|
||||||
|
for ( uint row = 0; row < numRows; row++ )
|
||||||
|
yDelta -= rowHeight[row];
|
||||||
|
|
||||||
|
if ( yDelta > 0 )
|
||||||
|
{
|
||||||
|
for ( uint row = 0; row < numRows; row++ )
|
||||||
|
{
|
||||||
|
const int space = yDelta / ( numRows - row );
|
||||||
|
rowHeight[row] += space;
|
||||||
|
yDelta -= space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return the size hint. If maxColumns() > 0 it is the size for
|
||||||
|
a grid with maxColumns() columns, otherwise it is the size for
|
||||||
|
a grid with only one row.
|
||||||
|
|
||||||
|
\return Size hint
|
||||||
|
\sa maxColumns(), setMaxColumns()
|
||||||
|
*/
|
||||||
|
QSize QwtDynGridLayout::sizeHint() const
|
||||||
|
{
|
||||||
|
if ( isEmpty() )
|
||||||
|
return QSize();
|
||||||
|
|
||||||
|
uint numColumns = itemCount();
|
||||||
|
if ( d_data->maxColumns > 0 )
|
||||||
|
numColumns = qMin( d_data->maxColumns, numColumns );
|
||||||
|
|
||||||
|
uint numRows = itemCount() / numColumns;
|
||||||
|
if ( itemCount() % numColumns )
|
||||||
|
numRows++;
|
||||||
|
|
||||||
|
QVector<int> rowHeight( numRows );
|
||||||
|
QVector<int> colWidth( numColumns );
|
||||||
|
|
||||||
|
layoutGrid( numColumns, rowHeight, colWidth );
|
||||||
|
|
||||||
|
int h = 2 * margin() + ( numRows - 1 ) * spacing();
|
||||||
|
for ( uint row = 0; row < numRows; row++ )
|
||||||
|
h += rowHeight[row];
|
||||||
|
|
||||||
|
int w = 2 * margin() + ( numColumns - 1 ) * spacing();
|
||||||
|
for ( uint col = 0; col < numColumns; col++ )
|
||||||
|
w += colWidth[col];
|
||||||
|
|
||||||
|
return QSize( w, h );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of rows of the current layout.
|
||||||
|
\sa numColumns()
|
||||||
|
\warning The number of rows might change whenever the geometry changes
|
||||||
|
*/
|
||||||
|
uint QwtDynGridLayout::numRows() const
|
||||||
|
{
|
||||||
|
return d_data->numRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of columns of the current layout.
|
||||||
|
\sa numRows()
|
||||||
|
\warning The number of columns might change whenever the geometry changes
|
||||||
|
*/
|
||||||
|
uint QwtDynGridLayout::numColumns() const
|
||||||
|
{
|
||||||
|
return d_data->numColumns;
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_DYNGRID_LAYOUT_H
|
||||||
|
#define QWT_DYNGRID_LAYOUT_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qlayout.h>
|
||||||
|
#include <qsize.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The QwtDynGridLayout class lays out widgets in a grid,
|
||||||
|
adjusting the number of columns and rows to the current size.
|
||||||
|
|
||||||
|
QwtDynGridLayout takes the space it gets, divides it up into rows and
|
||||||
|
columns, and puts each of the widgets it manages into the correct cell(s).
|
||||||
|
It lays out as many number of columns as possible (limited by maxColumns()).
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtDynGridLayout : public QLayout
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit QwtDynGridLayout( QWidget *, int margin = 0, int spacing = -1 );
|
||||||
|
explicit QwtDynGridLayout( int spacing = -1 );
|
||||||
|
|
||||||
|
virtual ~QwtDynGridLayout();
|
||||||
|
|
||||||
|
virtual void invalidate();
|
||||||
|
|
||||||
|
void setMaxColumns( uint maxColumns );
|
||||||
|
uint maxColumns() const;
|
||||||
|
|
||||||
|
uint numRows () const;
|
||||||
|
uint numColumns () const;
|
||||||
|
|
||||||
|
virtual void addItem( QLayoutItem * );
|
||||||
|
|
||||||
|
virtual QLayoutItem *itemAt( int index ) const;
|
||||||
|
virtual QLayoutItem *takeAt( int index );
|
||||||
|
virtual int count() const;
|
||||||
|
|
||||||
|
void setExpandingDirections( Qt::Orientations );
|
||||||
|
virtual Qt::Orientations expandingDirections() const;
|
||||||
|
QList<QRect> layoutItems( const QRect &, uint numColumns ) const;
|
||||||
|
|
||||||
|
virtual int maxItemWidth() const;
|
||||||
|
|
||||||
|
virtual void setGeometry( const QRect &rect );
|
||||||
|
|
||||||
|
virtual bool hasHeightForWidth() const;
|
||||||
|
virtual int heightForWidth( int ) const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
uint itemCount() const;
|
||||||
|
|
||||||
|
virtual uint columnsForWidth( int width ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void layoutGrid( uint numColumns,
|
||||||
|
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
|
||||||
|
void stretchGrid( const QRect &rect, uint numColumns,
|
||||||
|
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
int maxRowWidth( int numColumns ) const;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,265 @@
|
|||||||
|
/* -*- 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 "qwt_event_pattern.h"
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\sa MousePatternCode, KeyPatternCode
|
||||||
|
*/
|
||||||
|
|
||||||
|
QwtEventPattern::QwtEventPattern():
|
||||||
|
d_mousePattern( MousePatternCount ),
|
||||||
|
d_keyPattern( KeyPatternCount )
|
||||||
|
{
|
||||||
|
initKeyPattern();
|
||||||
|
initMousePattern( 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtEventPattern::~QwtEventPattern()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set default mouse patterns, depending on the number of mouse buttons
|
||||||
|
|
||||||
|
\param numButtons Number of mouse buttons ( <= 3 )
|
||||||
|
\sa MousePatternCode
|
||||||
|
*/
|
||||||
|
void QwtEventPattern::initMousePattern( int numButtons )
|
||||||
|
{
|
||||||
|
d_mousePattern.resize( MousePatternCount );
|
||||||
|
|
||||||
|
switch ( numButtons )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||||
|
setMousePattern( MouseSelect2, Qt::LeftButton, Qt::ControlModifier );
|
||||||
|
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||||
|
setMousePattern( MouseSelect2, Qt::RightButton );
|
||||||
|
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||||
|
setMousePattern( MouseSelect2, Qt::RightButton );
|
||||||
|
setMousePattern( MouseSelect3, Qt::MidButton );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMousePattern( MouseSelect4, d_mousePattern[MouseSelect1].button,
|
||||||
|
d_mousePattern[MouseSelect1].modifiers | Qt::ShiftModifier );
|
||||||
|
|
||||||
|
setMousePattern( MouseSelect5, d_mousePattern[MouseSelect2].button,
|
||||||
|
d_mousePattern[MouseSelect2].modifiers | Qt::ShiftModifier );
|
||||||
|
|
||||||
|
setMousePattern( MouseSelect6, d_mousePattern[MouseSelect3].button,
|
||||||
|
d_mousePattern[MouseSelect3].modifiers | Qt::ShiftModifier );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set default mouse patterns.
|
||||||
|
|
||||||
|
\sa KeyPatternCode
|
||||||
|
*/
|
||||||
|
void QwtEventPattern::initKeyPattern()
|
||||||
|
{
|
||||||
|
d_keyPattern.resize( KeyPatternCount );
|
||||||
|
|
||||||
|
setKeyPattern( KeySelect1, Qt::Key_Return );
|
||||||
|
setKeyPattern( KeySelect2, Qt::Key_Space );
|
||||||
|
setKeyPattern( KeyAbort, Qt::Key_Escape );
|
||||||
|
|
||||||
|
setKeyPattern( KeyLeft, Qt::Key_Left );
|
||||||
|
setKeyPattern( KeyRight, Qt::Key_Right );
|
||||||
|
setKeyPattern( KeyUp, Qt::Key_Up );
|
||||||
|
setKeyPattern( KeyDown, Qt::Key_Down );
|
||||||
|
|
||||||
|
setKeyPattern( KeyRedo, Qt::Key_Plus );
|
||||||
|
setKeyPattern( KeyUndo, Qt::Key_Minus );
|
||||||
|
setKeyPattern( KeyHome, Qt::Key_Escape );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change one mouse pattern
|
||||||
|
|
||||||
|
\param pattern Index of the pattern
|
||||||
|
\param button Button
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
|
||||||
|
\sa QMouseEvent
|
||||||
|
*/
|
||||||
|
void QwtEventPattern::setMousePattern( MousePatternCode pattern,
|
||||||
|
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
if ( pattern >= 0 && pattern < MousePatternCount )
|
||||||
|
{
|
||||||
|
d_mousePattern[ pattern ].button = button;
|
||||||
|
d_mousePattern[ pattern ].modifiers = modifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change one key pattern
|
||||||
|
|
||||||
|
\param pattern Index of the pattern
|
||||||
|
\param key Key
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
|
||||||
|
\sa QKeyEvent
|
||||||
|
*/
|
||||||
|
void QwtEventPattern::setKeyPattern( KeyPatternCode pattern,
|
||||||
|
int key, Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
if ( pattern >= 0 && pattern < KeyPatternCount )
|
||||||
|
{
|
||||||
|
d_keyPattern[ pattern ].key = key;
|
||||||
|
d_keyPattern[ pattern ].modifiers = modifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Change the mouse event patterns
|
||||||
|
void QwtEventPattern::setMousePattern( const QVector<MousePattern> &pattern )
|
||||||
|
{
|
||||||
|
d_mousePattern = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Change the key event patterns
|
||||||
|
void QwtEventPattern::setKeyPattern( const QVector<KeyPattern> &pattern )
|
||||||
|
{
|
||||||
|
d_keyPattern = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Mouse pattern
|
||||||
|
const QVector<QwtEventPattern::MousePattern> &
|
||||||
|
QwtEventPattern::mousePattern() const
|
||||||
|
{
|
||||||
|
return d_mousePattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Key pattern
|
||||||
|
const QVector<QwtEventPattern::KeyPattern> &
|
||||||
|
QwtEventPattern::keyPattern() const
|
||||||
|
{
|
||||||
|
return d_keyPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Mouse pattern
|
||||||
|
QVector<QwtEventPattern::MousePattern> &QwtEventPattern::mousePattern()
|
||||||
|
{
|
||||||
|
return d_mousePattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Key pattern
|
||||||
|
QVector<QwtEventPattern::KeyPattern> &QwtEventPattern::keyPattern()
|
||||||
|
{
|
||||||
|
return d_keyPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare a mouse event with an event pattern.
|
||||||
|
|
||||||
|
A mouse event matches the pattern when both have the same button
|
||||||
|
value and in the state value the same key flags(Qt::KeyButtonMask)
|
||||||
|
are set.
|
||||||
|
|
||||||
|
\param code Index of the event pattern
|
||||||
|
\param event Mouse event
|
||||||
|
\return true if matches
|
||||||
|
|
||||||
|
\sa keyMatch()
|
||||||
|
*/
|
||||||
|
bool QwtEventPattern::mouseMatch( MousePatternCode code,
|
||||||
|
const QMouseEvent *event ) const
|
||||||
|
{
|
||||||
|
if ( code >= 0 && code < MousePatternCount )
|
||||||
|
return mouseMatch( d_mousePattern[ code ], event );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare a mouse event with an event pattern.
|
||||||
|
|
||||||
|
A mouse event matches the pattern when both have the same button
|
||||||
|
value and in the state value the same key flags(Qt::KeyButtonMask)
|
||||||
|
are set.
|
||||||
|
|
||||||
|
\param pattern Mouse event pattern
|
||||||
|
\param event Mouse event
|
||||||
|
\return true if matches
|
||||||
|
|
||||||
|
\sa keyMatch()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QwtEventPattern::mouseMatch( const MousePattern &pattern,
|
||||||
|
const QMouseEvent *event ) const
|
||||||
|
{
|
||||||
|
if ( event == NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const MousePattern mousePattern( event->button(), event->modifiers() );
|
||||||
|
return mousePattern == pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare a key event with an event pattern.
|
||||||
|
|
||||||
|
A key event matches the pattern when both have the same key
|
||||||
|
value and in the state value the same key flags (Qt::KeyButtonMask)
|
||||||
|
are set.
|
||||||
|
|
||||||
|
\param code Index of the event pattern
|
||||||
|
\param event Key event
|
||||||
|
\return true if matches
|
||||||
|
|
||||||
|
\sa mouseMatch()
|
||||||
|
*/
|
||||||
|
bool QwtEventPattern::keyMatch( KeyPatternCode code,
|
||||||
|
const QKeyEvent *event ) const
|
||||||
|
{
|
||||||
|
if ( code >= 0 && code < KeyPatternCount )
|
||||||
|
return keyMatch( d_keyPattern[ code ], event );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare a key event with an event pattern.
|
||||||
|
|
||||||
|
A key event matches the pattern when both have the same key
|
||||||
|
value and in the state value the same key flags (Qt::KeyButtonMask)
|
||||||
|
are set.
|
||||||
|
|
||||||
|
\param pattern Key event pattern
|
||||||
|
\param event Key event
|
||||||
|
\return true if matches
|
||||||
|
|
||||||
|
\sa mouseMatch()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QwtEventPattern::keyMatch(
|
||||||
|
const KeyPattern &pattern, const QKeyEvent *event ) const
|
||||||
|
{
|
||||||
|
if ( event == NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const KeyPattern keyPattern( event->key(), event->modifiers() );
|
||||||
|
return keyPattern == pattern;
|
||||||
|
}
|
||||||
@ -0,0 +1,240 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_EVENT_PATTERN
|
||||||
|
#define QWT_EVENT_PATTERN 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
class QMouseEvent;
|
||||||
|
class QKeyEvent;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A collection of event patterns
|
||||||
|
|
||||||
|
QwtEventPattern introduces an level of indirection for mouse and
|
||||||
|
keyboard inputs. Those are represented by symbolic names, so
|
||||||
|
the application code can be configured by individual mappings.
|
||||||
|
|
||||||
|
\sa QwtPicker, QwtPickerMachine, QwtPlotZoomer
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtEventPattern
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
\brief Symbolic mouse input codes
|
||||||
|
|
||||||
|
QwtEventPattern implements 3 different settings for
|
||||||
|
mice with 1, 2, or 3 buttons that can be activated
|
||||||
|
using initMousePattern(). The default setting is for
|
||||||
|
3 button mice.
|
||||||
|
|
||||||
|
Individual settings can be configured using setMousePattern().
|
||||||
|
|
||||||
|
\sa initMousePattern(), setMousePattern(), setKeyPattern()
|
||||||
|
*/
|
||||||
|
enum MousePatternCode
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton
|
||||||
|
- Qt::LeftButton
|
||||||
|
- Qt::LeftButton
|
||||||
|
*/
|
||||||
|
MouseSelect1,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton + Qt::ControlModifier
|
||||||
|
- Qt::RightButton
|
||||||
|
- Qt::RightButton
|
||||||
|
*/
|
||||||
|
MouseSelect2,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton + Qt::AltModifier
|
||||||
|
- Qt::LeftButton + Qt::AltModifier
|
||||||
|
- Qt::MidButton
|
||||||
|
*/
|
||||||
|
MouseSelect3,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton + Qt::ShiftModifier
|
||||||
|
- Qt::LeftButton + Qt::ShiftModifier
|
||||||
|
- Qt::LeftButton + Qt::ShiftModifier
|
||||||
|
*/
|
||||||
|
MouseSelect4,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton + Qt::ControlButton | Qt::ShiftModifier
|
||||||
|
- Qt::RightButton + Qt::ShiftModifier
|
||||||
|
- Qt::RightButton + Qt::ShiftModifier
|
||||||
|
*/
|
||||||
|
MouseSelect5,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default setting for 1, 2 and 3 button mice is:
|
||||||
|
|
||||||
|
- Qt::LeftButton + Qt::AltModifier + Qt::ShiftModifier
|
||||||
|
- Qt::LeftButton + Qt::AltModifier | Qt::ShiftModifier
|
||||||
|
- Qt::MidButton + Qt::ShiftModifier
|
||||||
|
*/
|
||||||
|
MouseSelect6,
|
||||||
|
|
||||||
|
//! Number of mouse patterns
|
||||||
|
MousePatternCount
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Symbolic keyboard input codes
|
||||||
|
|
||||||
|
Individual settings can be configured using setKeyPattern()
|
||||||
|
|
||||||
|
\sa setKeyPattern(), setMousePattern()
|
||||||
|
*/
|
||||||
|
enum KeyPatternCode
|
||||||
|
{
|
||||||
|
//! Qt::Key_Return
|
||||||
|
KeySelect1,
|
||||||
|
|
||||||
|
//! Qt::Key_Space
|
||||||
|
KeySelect2,
|
||||||
|
|
||||||
|
//! Qt::Key_Escape
|
||||||
|
KeyAbort,
|
||||||
|
|
||||||
|
//! Qt::Key_Left
|
||||||
|
KeyLeft,
|
||||||
|
|
||||||
|
//! Qt::Key_Right
|
||||||
|
KeyRight,
|
||||||
|
|
||||||
|
//! Qt::Key_Up
|
||||||
|
KeyUp,
|
||||||
|
|
||||||
|
//! Qt::Key_Down
|
||||||
|
KeyDown,
|
||||||
|
|
||||||
|
//! Qt::Key_Plus
|
||||||
|
KeyRedo,
|
||||||
|
|
||||||
|
//! Qt::Key_Minus
|
||||||
|
KeyUndo,
|
||||||
|
|
||||||
|
//! Qt::Key_Escape
|
||||||
|
KeyHome,
|
||||||
|
|
||||||
|
//! Number of key patterns
|
||||||
|
KeyPatternCount
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A pattern for mouse events
|
||||||
|
class MousePattern
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Constructor
|
||||||
|
MousePattern( Qt::MouseButton btn = Qt::NoButton,
|
||||||
|
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
|
||||||
|
button( btn ),
|
||||||
|
modifiers( modifierCodes )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Button
|
||||||
|
Qt::MouseButton button;
|
||||||
|
|
||||||
|
//! Keyboard modifier
|
||||||
|
Qt::KeyboardModifiers modifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A pattern for key events
|
||||||
|
class KeyPattern
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Constructor
|
||||||
|
KeyPattern( int keyCode = Qt::Key_unknown,
|
||||||
|
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
|
||||||
|
key( keyCode ),
|
||||||
|
modifiers( modifierCodes )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Key code
|
||||||
|
int key;
|
||||||
|
|
||||||
|
//! Modifiers
|
||||||
|
Qt::KeyboardModifiers modifiers;
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtEventPattern();
|
||||||
|
virtual ~QwtEventPattern();
|
||||||
|
|
||||||
|
void initMousePattern( int numButtons );
|
||||||
|
void initKeyPattern();
|
||||||
|
|
||||||
|
void setMousePattern( MousePatternCode, Qt::MouseButton button,
|
||||||
|
Qt::KeyboardModifiers = Qt::NoModifier );
|
||||||
|
|
||||||
|
void setKeyPattern( KeyPatternCode, int key,
|
||||||
|
Qt::KeyboardModifiers modifiers = Qt::NoModifier );
|
||||||
|
|
||||||
|
void setMousePattern( const QVector<MousePattern> & );
|
||||||
|
void setKeyPattern( const QVector<KeyPattern> & );
|
||||||
|
|
||||||
|
const QVector<MousePattern> &mousePattern() const;
|
||||||
|
const QVector<KeyPattern> &keyPattern() const;
|
||||||
|
|
||||||
|
QVector<MousePattern> &mousePattern();
|
||||||
|
QVector<KeyPattern> &keyPattern();
|
||||||
|
|
||||||
|
bool mouseMatch( MousePatternCode, const QMouseEvent * ) const;
|
||||||
|
bool keyMatch( KeyPatternCode, const QKeyEvent * ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool mouseMatch( const MousePattern &, const QMouseEvent * ) const;
|
||||||
|
virtual bool keyMatch( const KeyPattern &, const QKeyEvent * ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4251)
|
||||||
|
#endif
|
||||||
|
QVector<MousePattern> d_mousePattern;
|
||||||
|
QVector<KeyPattern> d_keyPattern;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Compare operator
|
||||||
|
inline bool operator==( QwtEventPattern::MousePattern b1,
|
||||||
|
QwtEventPattern::MousePattern b2 )
|
||||||
|
{
|
||||||
|
return b1.button == b2.button && b1.modifiers == b2.modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Compare operator
|
||||||
|
inline bool operator==( QwtEventPattern::KeyPattern b1,
|
||||||
|
QwtEventPattern::KeyPattern b2 )
|
||||||
|
{
|
||||||
|
return b1.key == b2.key && b1.modifiers == b2.modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_GLOBAL_H
|
||||||
|
#define QWT_GLOBAL_H
|
||||||
|
|
||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
|
// QWT_VERSION is (major << 16) + (minor << 8) + patch.
|
||||||
|
|
||||||
|
#define QWT_VERSION 0x060104
|
||||||
|
#define QWT_VERSION_STR "6.1.4"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) /* MSVC Compiler */
|
||||||
|
/* template-class specialization 'identifier' is already instantiated */
|
||||||
|
#pragma warning(disable: 4660)
|
||||||
|
/* inherits via dominance */
|
||||||
|
#pragma warning(disable: 4250)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#ifdef QWT_DLL
|
||||||
|
|
||||||
|
#if defined(QWT_MAKEDLL) // create a Qwt DLL library
|
||||||
|
#define QWT_EXPORT Q_DECL_EXPORT
|
||||||
|
#else // use a Qwt DLL library
|
||||||
|
#define QWT_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // QWT_DLL
|
||||||
|
|
||||||
|
#ifndef QWT_EXPORT
|
||||||
|
#define QWT_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,176 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_GRAPHIC_H
|
||||||
|
#define QWT_GRAPHIC_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_null_paintdevice.h"
|
||||||
|
#include <qmetatype.h>
|
||||||
|
#include <qimage.h>
|
||||||
|
#include <qpixmap.h>
|
||||||
|
|
||||||
|
class QwtPainterCommand;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A paint device for scalable graphics
|
||||||
|
|
||||||
|
QwtGraphic is the representation of a graphic that is tailored for
|
||||||
|
scalability. Like QPicture it will be initialized by QPainter
|
||||||
|
operations and can be replayed later to any target paint device.
|
||||||
|
|
||||||
|
While the usual image representations QImage and QPixmap are not
|
||||||
|
scalable Qt offers two paint devices, that might be candidates
|
||||||
|
for representing a vector graphic:
|
||||||
|
|
||||||
|
- QPicture\n
|
||||||
|
Unfortunately QPicture had been forgotten, when Qt4
|
||||||
|
introduced floating point based render engines. Its API
|
||||||
|
is still on integers, what make it unusable for proper scaling.
|
||||||
|
|
||||||
|
- QSvgRenderer/QSvgGenerator\n
|
||||||
|
Unfortunately QSvgRenderer hides to much information about
|
||||||
|
its nodes in internal APIs, that are necessary for proper
|
||||||
|
layout calculations. Also it is derived from QObject and
|
||||||
|
can't be copied like QImage/QPixmap.
|
||||||
|
|
||||||
|
QwtGraphic maps all scalable drawing primitives to a QPainterPath
|
||||||
|
and stores them together with the painter state changes
|
||||||
|
( pen, brush, transformation ... ) in a list of QwtPaintCommands.
|
||||||
|
For being a complete QPaintDevice it also stores pixmaps or images,
|
||||||
|
what is somehow against the idea of the class, because these objects
|
||||||
|
can't be scaled without a loss in quality.
|
||||||
|
|
||||||
|
The main issue about scaling a QwtGraphic object are the pens used for
|
||||||
|
drawing the outlines of the painter paths. While non cosmetic pens
|
||||||
|
( QPen::isCosmetic() ) are scaled with the same ratio as the path,
|
||||||
|
cosmetic pens have a fixed width. A graphic might have paths with
|
||||||
|
different pens - cosmetic and non-cosmetic.
|
||||||
|
|
||||||
|
QwtGraphic caches 2 different rectangles:
|
||||||
|
|
||||||
|
- control point rectangle\n
|
||||||
|
The control point rectangle is the bounding rectangle of all
|
||||||
|
control point rectangles of the painter paths, or the target
|
||||||
|
rectangle of the pixmaps/images.
|
||||||
|
|
||||||
|
- bounding rectangle\n
|
||||||
|
The bounding rectangle extends the control point rectangle by
|
||||||
|
what is needed for rendering the outline with an unscaled pen.
|
||||||
|
|
||||||
|
Because the offset for drawing the outline depends on the shape
|
||||||
|
of the painter path ( the peak of a triangle is different than the flat side )
|
||||||
|
scaling with a fixed aspect ratio always needs to be calculated from the
|
||||||
|
control point rectangle.
|
||||||
|
|
||||||
|
\sa QwtPainterCommand
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtGraphic: public QwtNullPaintDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Hint how to render a graphic
|
||||||
|
\sa setRenderHint(), testRenderHint()
|
||||||
|
*/
|
||||||
|
enum RenderHint
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
When rendering a QwtGraphic a specific scaling between
|
||||||
|
the controlPointRect() and the coordinates of the target rectangle
|
||||||
|
is set up internally in render().
|
||||||
|
|
||||||
|
When RenderPensUnscaled is set this specific scaling is applied
|
||||||
|
for the control points only, but not for the pens.
|
||||||
|
All other painter transformations ( set up by application code )
|
||||||
|
are supposed to work like usual.
|
||||||
|
|
||||||
|
\sa render();
|
||||||
|
*/
|
||||||
|
RenderPensUnscaled = 0x1
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Render hints
|
||||||
|
|
||||||
|
The default setting is to disable all hints
|
||||||
|
*/
|
||||||
|
typedef QFlags<RenderHint> RenderHints;
|
||||||
|
|
||||||
|
QwtGraphic();
|
||||||
|
QwtGraphic( const QwtGraphic & );
|
||||||
|
|
||||||
|
virtual ~QwtGraphic();
|
||||||
|
|
||||||
|
QwtGraphic& operator=( const QwtGraphic & );
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
bool isNull() const;
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
void render( QPainter * ) const;
|
||||||
|
|
||||||
|
void render( QPainter *, const QSizeF &,
|
||||||
|
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||||
|
|
||||||
|
void render( QPainter *, const QRectF &,
|
||||||
|
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||||
|
|
||||||
|
void render( QPainter *, const QPointF &,
|
||||||
|
Qt::Alignment = Qt::AlignTop | Qt::AlignLeft ) const;
|
||||||
|
|
||||||
|
QPixmap toPixmap() const;
|
||||||
|
QPixmap toPixmap( const QSize &,
|
||||||
|
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||||
|
|
||||||
|
QImage toImage() const;
|
||||||
|
QImage toImage( const QSize &,
|
||||||
|
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||||
|
|
||||||
|
QRectF scaledBoundingRect( double sx, double sy ) const;
|
||||||
|
|
||||||
|
QRectF boundingRect() const;
|
||||||
|
QRectF controlPointRect() const;
|
||||||
|
|
||||||
|
const QVector< QwtPainterCommand > &commands() const;
|
||||||
|
void setCommands( QVector< QwtPainterCommand > & );
|
||||||
|
|
||||||
|
void setDefaultSize( const QSizeF & );
|
||||||
|
QSizeF defaultSize() const;
|
||||||
|
|
||||||
|
void setRenderHint( RenderHint, bool on = true );
|
||||||
|
bool testRenderHint( RenderHint ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QSize sizeMetrics() const;
|
||||||
|
|
||||||
|
virtual void drawPath( const QPainterPath & );
|
||||||
|
|
||||||
|
virtual void drawPixmap( const QRectF &,
|
||||||
|
const QPixmap &, const QRectF & );
|
||||||
|
|
||||||
|
virtual void drawImage( const QRectF &,
|
||||||
|
const QImage &, const QRectF &, Qt::ImageConversionFlags );
|
||||||
|
|
||||||
|
virtual void updateState( const QPaintEngineState &state );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateBoundingRect( const QRectF & );
|
||||||
|
void updateControlPointRect( const QRectF & );
|
||||||
|
|
||||||
|
class PathInfo;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtGraphic::RenderHints )
|
||||||
|
Q_DECLARE_METATYPE( QwtGraphic )
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,354 @@
|
|||||||
|
/* -*- 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 "qwt_interval.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include <qalgorithms.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Normalize the limits of the interval
|
||||||
|
|
||||||
|
If maxValue() < minValue() the limits will be inverted.
|
||||||
|
\return Normalized interval
|
||||||
|
|
||||||
|
\sa isValid(), inverted()
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::normalized() const
|
||||||
|
{
|
||||||
|
if ( d_minValue > d_maxValue )
|
||||||
|
{
|
||||||
|
return inverted();
|
||||||
|
}
|
||||||
|
if ( d_minValue == d_maxValue && d_borderFlags == ExcludeMinimum )
|
||||||
|
{
|
||||||
|
return inverted();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invert the limits of the interval
|
||||||
|
\return Inverted interval
|
||||||
|
\sa normalized()
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::inverted() const
|
||||||
|
{
|
||||||
|
BorderFlags borderFlags = IncludeBorders;
|
||||||
|
if ( d_borderFlags & ExcludeMinimum )
|
||||||
|
borderFlags |= ExcludeMaximum;
|
||||||
|
if ( d_borderFlags & ExcludeMaximum )
|
||||||
|
borderFlags |= ExcludeMinimum;
|
||||||
|
|
||||||
|
return QwtInterval( d_maxValue, d_minValue, borderFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Test if a value is inside an interval
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\return true, if value >= minValue() && value <= maxValue()
|
||||||
|
*/
|
||||||
|
bool QwtInterval::contains( double value ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( value < d_minValue || value > d_maxValue )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( value == d_minValue && d_borderFlags & ExcludeMinimum )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( value == d_maxValue && d_borderFlags & ExcludeMaximum )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Unite 2 intervals
|
||||||
|
QwtInterval QwtInterval::unite( const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If one of the intervals is invalid return the other one.
|
||||||
|
If both are invalid return an invalid default interval
|
||||||
|
*/
|
||||||
|
if ( !isValid() )
|
||||||
|
{
|
||||||
|
if ( !other.isValid() )
|
||||||
|
return QwtInterval();
|
||||||
|
else
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
if ( !other.isValid() )
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
QwtInterval united;
|
||||||
|
BorderFlags flags = IncludeBorders;
|
||||||
|
|
||||||
|
// minimum
|
||||||
|
if ( d_minValue < other.minValue() )
|
||||||
|
{
|
||||||
|
united.setMinValue( d_minValue );
|
||||||
|
flags &= d_borderFlags & ExcludeMinimum;
|
||||||
|
}
|
||||||
|
else if ( other.minValue() < d_minValue )
|
||||||
|
{
|
||||||
|
united.setMinValue( other.minValue() );
|
||||||
|
flags &= other.borderFlags() & ExcludeMinimum;
|
||||||
|
}
|
||||||
|
else // d_minValue == other.minValue()
|
||||||
|
{
|
||||||
|
united.setMinValue( d_minValue );
|
||||||
|
flags &= ( d_borderFlags & other.borderFlags() ) & ExcludeMinimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maximum
|
||||||
|
if ( d_maxValue > other.maxValue() )
|
||||||
|
{
|
||||||
|
united.setMaxValue( d_maxValue );
|
||||||
|
flags &= d_borderFlags & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
else if ( other.maxValue() > d_maxValue )
|
||||||
|
{
|
||||||
|
united.setMaxValue( other.maxValue() );
|
||||||
|
flags &= other.borderFlags() & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
else // d_maxValue == other.maxValue() )
|
||||||
|
{
|
||||||
|
united.setMaxValue( d_maxValue );
|
||||||
|
flags &= d_borderFlags & other.borderFlags() & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
united.setBorderFlags( flags );
|
||||||
|
return united;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Intersect 2 intervals
|
||||||
|
|
||||||
|
\param other Interval to be intersect with
|
||||||
|
\return Intersection
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::intersect( const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
if ( !other.isValid() || !isValid() )
|
||||||
|
return QwtInterval();
|
||||||
|
|
||||||
|
QwtInterval i1 = *this;
|
||||||
|
QwtInterval i2 = other;
|
||||||
|
|
||||||
|
// swap i1/i2, so that the minimum of i1
|
||||||
|
// is smaller then the minimum of i2
|
||||||
|
|
||||||
|
if ( i1.minValue() > i2.minValue() )
|
||||||
|
{
|
||||||
|
qSwap( i1, i2 );
|
||||||
|
}
|
||||||
|
else if ( i1.minValue() == i2.minValue() )
|
||||||
|
{
|
||||||
|
if ( i1.borderFlags() & ExcludeMinimum )
|
||||||
|
qSwap( i1, i2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i1.maxValue() < i2.minValue() )
|
||||||
|
{
|
||||||
|
return QwtInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i1.maxValue() == i2.minValue() )
|
||||||
|
{
|
||||||
|
if ( i1.borderFlags() & ExcludeMaximum ||
|
||||||
|
i2.borderFlags() & ExcludeMinimum )
|
||||||
|
{
|
||||||
|
return QwtInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtInterval intersected;
|
||||||
|
BorderFlags flags = IncludeBorders;
|
||||||
|
|
||||||
|
intersected.setMinValue( i2.minValue() );
|
||||||
|
flags |= i2.borderFlags() & ExcludeMinimum;
|
||||||
|
|
||||||
|
if ( i1.maxValue() < i2.maxValue() )
|
||||||
|
{
|
||||||
|
intersected.setMaxValue( i1.maxValue() );
|
||||||
|
flags |= i1.borderFlags() & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
else if ( i2.maxValue() < i1.maxValue() )
|
||||||
|
{
|
||||||
|
intersected.setMaxValue( i2.maxValue() );
|
||||||
|
flags |= i2.borderFlags() & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
else // i1.maxValue() == i2.maxValue()
|
||||||
|
{
|
||||||
|
intersected.setMaxValue( i1.maxValue() );
|
||||||
|
flags |= i1.borderFlags() & i2.borderFlags() & ExcludeMaximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
intersected.setBorderFlags( flags );
|
||||||
|
return intersected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Unite this interval with the given interval.
|
||||||
|
|
||||||
|
\param other Interval to be united with
|
||||||
|
\return This interval
|
||||||
|
*/
|
||||||
|
QwtInterval& QwtInterval::operator|=( const QwtInterval &other )
|
||||||
|
{
|
||||||
|
*this = *this | other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Intersect this interval with the given interval.
|
||||||
|
|
||||||
|
\param other Interval to be intersected with
|
||||||
|
\return This interval
|
||||||
|
*/
|
||||||
|
QwtInterval& QwtInterval::operator&=( const QwtInterval &other )
|
||||||
|
{
|
||||||
|
*this = *this & other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Test if two intervals overlap
|
||||||
|
|
||||||
|
\param other Interval
|
||||||
|
\return True, when the intervals are intersecting
|
||||||
|
*/
|
||||||
|
bool QwtInterval::intersects( const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() || !other.isValid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QwtInterval i1 = *this;
|
||||||
|
QwtInterval i2 = other;
|
||||||
|
|
||||||
|
// swap i1/i2, so that the minimum of i1
|
||||||
|
// is smaller then the minimum of i2
|
||||||
|
|
||||||
|
if ( i1.minValue() > i2.minValue() )
|
||||||
|
{
|
||||||
|
qSwap( i1, i2 );
|
||||||
|
}
|
||||||
|
else if ( i1.minValue() == i2.minValue() &&
|
||||||
|
i1.borderFlags() & ExcludeMinimum )
|
||||||
|
{
|
||||||
|
qSwap( i1, i2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( i1.maxValue() > i2.minValue() )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( i1.maxValue() == i2.minValue() )
|
||||||
|
{
|
||||||
|
return !( ( i1.borderFlags() & ExcludeMaximum ) ||
|
||||||
|
( i2.borderFlags() & ExcludeMinimum ) );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Adjust the limit that is closer to value, so that value becomes
|
||||||
|
the center of the interval.
|
||||||
|
|
||||||
|
\param value Center
|
||||||
|
\return Interval with value as center
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::symmetrize( double value ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() )
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
const double delta =
|
||||||
|
qMax( qAbs( value - d_maxValue ), qAbs( value - d_minValue ) );
|
||||||
|
|
||||||
|
return QwtInterval( value - delta, value + delta );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Limit the interval, keeping the border modes
|
||||||
|
|
||||||
|
\param lowerBound Lower limit
|
||||||
|
\param upperBound Upper limit
|
||||||
|
|
||||||
|
\return Limited interval
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::limited( double lowerBound, double upperBound ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() || lowerBound > upperBound )
|
||||||
|
return QwtInterval();
|
||||||
|
|
||||||
|
double minValue = qMax( d_minValue, lowerBound );
|
||||||
|
minValue = qMin( minValue, upperBound );
|
||||||
|
|
||||||
|
double maxValue = qMax( d_maxValue, lowerBound );
|
||||||
|
maxValue = qMin( maxValue, upperBound );
|
||||||
|
|
||||||
|
return QwtInterval( minValue, maxValue, d_borderFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Extend the interval
|
||||||
|
|
||||||
|
If value is below minValue(), value becomes the lower limit.
|
||||||
|
If value is above maxValue(), value becomes the upper limit.
|
||||||
|
|
||||||
|
extend() has no effect for invalid intervals
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\return extended interval
|
||||||
|
|
||||||
|
\sa isValid()
|
||||||
|
*/
|
||||||
|
QwtInterval QwtInterval::extend( double value ) const
|
||||||
|
{
|
||||||
|
if ( !isValid() )
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
return QwtInterval( qMin( value, d_minValue ),
|
||||||
|
qMax( value, d_maxValue ), d_borderFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Extend an interval
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\return Reference of the extended interval
|
||||||
|
|
||||||
|
\sa extend()
|
||||||
|
*/
|
||||||
|
QwtInterval& QwtInterval::operator|=( double value )
|
||||||
|
{
|
||||||
|
*this = *this | value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
|
||||||
|
QDebug operator<<( QDebug debug, const QwtInterval &interval )
|
||||||
|
{
|
||||||
|
const int flags = interval.borderFlags();
|
||||||
|
|
||||||
|
debug.nospace() << "QwtInterval("
|
||||||
|
<< ( ( flags & QwtInterval::ExcludeMinimum ) ? "]" : "[" )
|
||||||
|
<< interval.minValue() << "," << interval.maxValue()
|
||||||
|
<< ( ( flags & QwtInterval::ExcludeMaximum ) ? "[" : "]" )
|
||||||
|
<< ")";
|
||||||
|
|
||||||
|
return debug.space();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,320 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_INTERVAL_H
|
||||||
|
#define QWT_INTERVAL_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qmetatype.h>
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
#include <qdebug.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A class representing an interval
|
||||||
|
|
||||||
|
The interval is represented by 2 doubles, the lower and the upper limit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtInterval
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Flag indicating if a border is included or excluded
|
||||||
|
\sa setBorderFlags(), borderFlags()
|
||||||
|
*/
|
||||||
|
enum BorderFlag
|
||||||
|
{
|
||||||
|
//! Min/Max values are inside the interval
|
||||||
|
IncludeBorders = 0x00,
|
||||||
|
|
||||||
|
//! Min value is not included in the interval
|
||||||
|
ExcludeMinimum = 0x01,
|
||||||
|
|
||||||
|
//! Max value is not included in the interval
|
||||||
|
ExcludeMaximum = 0x02,
|
||||||
|
|
||||||
|
//! Min/Max values are not included in the interval
|
||||||
|
ExcludeBorders = ExcludeMinimum | ExcludeMaximum
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Border flags
|
||||||
|
typedef QFlags<BorderFlag> BorderFlags;
|
||||||
|
|
||||||
|
QwtInterval();
|
||||||
|
QwtInterval( double minValue, double maxValue,
|
||||||
|
BorderFlags = IncludeBorders );
|
||||||
|
|
||||||
|
void setInterval( double minValue, double maxValue,
|
||||||
|
BorderFlags = IncludeBorders );
|
||||||
|
|
||||||
|
QwtInterval normalized() const;
|
||||||
|
QwtInterval inverted() const;
|
||||||
|
QwtInterval limited( double lowerBound, double upperBound ) const;
|
||||||
|
|
||||||
|
bool operator==( const QwtInterval & ) const;
|
||||||
|
bool operator!=( const QwtInterval & ) const;
|
||||||
|
|
||||||
|
void setBorderFlags( BorderFlags );
|
||||||
|
BorderFlags borderFlags() const;
|
||||||
|
|
||||||
|
double minValue() const;
|
||||||
|
double maxValue() const;
|
||||||
|
|
||||||
|
double width() const;
|
||||||
|
|
||||||
|
void setMinValue( double );
|
||||||
|
void setMaxValue( double );
|
||||||
|
|
||||||
|
bool contains( double value ) const;
|
||||||
|
|
||||||
|
bool intersects( const QwtInterval & ) const;
|
||||||
|
QwtInterval intersect( const QwtInterval & ) const;
|
||||||
|
QwtInterval unite( const QwtInterval & ) const;
|
||||||
|
|
||||||
|
QwtInterval operator|( const QwtInterval & ) const;
|
||||||
|
QwtInterval operator&( const QwtInterval & ) const;
|
||||||
|
|
||||||
|
QwtInterval &operator|=( const QwtInterval & );
|
||||||
|
QwtInterval &operator&=( const QwtInterval & );
|
||||||
|
|
||||||
|
QwtInterval extend( double value ) const;
|
||||||
|
QwtInterval operator|( double ) const;
|
||||||
|
QwtInterval &operator|=( double );
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
bool isNull() const;
|
||||||
|
void invalidate();
|
||||||
|
|
||||||
|
QwtInterval symmetrize( double value ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double d_minValue;
|
||||||
|
double d_maxValue;
|
||||||
|
BorderFlags d_borderFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_TYPEINFO(QwtInterval, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Default Constructor
|
||||||
|
|
||||||
|
Creates an invalid interval [0.0, -1.0]
|
||||||
|
\sa setInterval(), isValid()
|
||||||
|
*/
|
||||||
|
inline QwtInterval::QwtInterval():
|
||||||
|
d_minValue( 0.0 ),
|
||||||
|
d_maxValue( -1.0 ),
|
||||||
|
d_borderFlags( IncludeBorders )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
Build an interval with from min/max values
|
||||||
|
|
||||||
|
\param minValue Minimum value
|
||||||
|
\param maxValue Maximum value
|
||||||
|
\param borderFlags Include/Exclude borders
|
||||||
|
*/
|
||||||
|
inline QwtInterval::QwtInterval(
|
||||||
|
double minValue, double maxValue, BorderFlags borderFlags ):
|
||||||
|
d_minValue( minValue ),
|
||||||
|
d_maxValue( maxValue ),
|
||||||
|
d_borderFlags( borderFlags )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the limits of the interval
|
||||||
|
|
||||||
|
\param minValue Minimum value
|
||||||
|
\param maxValue Maximum value
|
||||||
|
\param borderFlags Include/Exclude borders
|
||||||
|
*/
|
||||||
|
inline void QwtInterval::setInterval(
|
||||||
|
double minValue, double maxValue, BorderFlags borderFlags )
|
||||||
|
{
|
||||||
|
d_minValue = minValue;
|
||||||
|
d_maxValue = maxValue;
|
||||||
|
d_borderFlags = borderFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the border flags
|
||||||
|
|
||||||
|
\param borderFlags Or'd BorderMode flags
|
||||||
|
\sa borderFlags()
|
||||||
|
*/
|
||||||
|
inline void QwtInterval::setBorderFlags( BorderFlags borderFlags )
|
||||||
|
{
|
||||||
|
d_borderFlags = borderFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Border flags
|
||||||
|
\sa setBorderFlags()
|
||||||
|
*/
|
||||||
|
inline QwtInterval::BorderFlags QwtInterval::borderFlags() const
|
||||||
|
{
|
||||||
|
return d_borderFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the lower limit of the interval
|
||||||
|
|
||||||
|
\param minValue Minimum value
|
||||||
|
*/
|
||||||
|
inline void QwtInterval::setMinValue( double minValue )
|
||||||
|
{
|
||||||
|
d_minValue = minValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the upper limit of the interval
|
||||||
|
|
||||||
|
\param maxValue Maximum value
|
||||||
|
*/
|
||||||
|
inline void QwtInterval::setMaxValue( double maxValue )
|
||||||
|
{
|
||||||
|
d_maxValue = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Lower limit of the interval
|
||||||
|
inline double QwtInterval::minValue() const
|
||||||
|
{
|
||||||
|
return d_minValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Upper limit of the interval
|
||||||
|
inline double QwtInterval::maxValue() const
|
||||||
|
{
|
||||||
|
return d_maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A interval is valid when minValue() <= maxValue().
|
||||||
|
In case of QwtInterval::ExcludeBorders it is true
|
||||||
|
when minValue() < maxValue()
|
||||||
|
|
||||||
|
\return True, when the interval is valid
|
||||||
|
*/
|
||||||
|
inline bool QwtInterval::isValid() const
|
||||||
|
{
|
||||||
|
if ( ( d_borderFlags & ExcludeBorders ) == 0 )
|
||||||
|
return d_minValue <= d_maxValue;
|
||||||
|
else
|
||||||
|
return d_minValue < d_maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Return the width of an interval
|
||||||
|
|
||||||
|
The width of invalid intervals is 0.0, otherwise the result is
|
||||||
|
maxValue() - minValue().
|
||||||
|
|
||||||
|
\return Interval width
|
||||||
|
\sa isValid()
|
||||||
|
*/
|
||||||
|
inline double QwtInterval::width() const
|
||||||
|
{
|
||||||
|
return isValid() ? ( d_maxValue - d_minValue ) : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Intersection of two intervals
|
||||||
|
|
||||||
|
\param other Interval to intersect with
|
||||||
|
\return Intersection of this and other
|
||||||
|
|
||||||
|
\sa intersect()
|
||||||
|
*/
|
||||||
|
inline QwtInterval QwtInterval::operator&(
|
||||||
|
const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
return intersect( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Union of two intervals
|
||||||
|
|
||||||
|
\param other Interval to unite with
|
||||||
|
\return Union of this and other
|
||||||
|
|
||||||
|
\sa unite()
|
||||||
|
*/
|
||||||
|
inline QwtInterval QwtInterval::operator|(
|
||||||
|
const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
return unite( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare two intervals
|
||||||
|
|
||||||
|
\param other Interval to compare with
|
||||||
|
\return True, when this and other are equal
|
||||||
|
*/
|
||||||
|
inline bool QwtInterval::operator==( const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
return ( d_minValue == other.d_minValue ) &&
|
||||||
|
( d_maxValue == other.d_maxValue ) &&
|
||||||
|
( d_borderFlags == other.d_borderFlags );
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
\brief Compare two intervals
|
||||||
|
|
||||||
|
\param other Interval to compare with
|
||||||
|
\return True, when this and other are not equal
|
||||||
|
*/
|
||||||
|
inline bool QwtInterval::operator!=( const QwtInterval &other ) const
|
||||||
|
{
|
||||||
|
return ( !( *this == other ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Extend an interval
|
||||||
|
|
||||||
|
\param value Value
|
||||||
|
\return Extended interval
|
||||||
|
\sa extend()
|
||||||
|
*/
|
||||||
|
inline QwtInterval QwtInterval::operator|( double value ) const
|
||||||
|
{
|
||||||
|
return extend( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return true, if isValid() && (minValue() >= maxValue())
|
||||||
|
inline bool QwtInterval::isNull() const
|
||||||
|
{
|
||||||
|
return isValid() && d_minValue >= d_maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invalidate the interval
|
||||||
|
|
||||||
|
The limits are set to interval [0.0, -1.0]
|
||||||
|
\sa isValid()
|
||||||
|
*/
|
||||||
|
inline void QwtInterval::invalidate()
|
||||||
|
{
|
||||||
|
d_minValue = 0.0;
|
||||||
|
d_maxValue = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtInterval::BorderFlags )
|
||||||
|
Q_DECLARE_METATYPE( QwtInterval )
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,319 @@
|
|||||||
|
/* -*- 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 "qwt_interval_symbol.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040601
|
||||||
|
#define qAtan2(y, x) ::atan2(y, x)
|
||||||
|
#define qFastSin(x) qSin(x)
|
||||||
|
#define qFastCos(x) qCos(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QwtIntervalSymbol::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
style( QwtIntervalSymbol::NoSymbol ),
|
||||||
|
width( 6 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==( const PrivateData &other ) const
|
||||||
|
{
|
||||||
|
return ( style == other.style )
|
||||||
|
&& ( width == other.width )
|
||||||
|
&& ( brush == other.brush )
|
||||||
|
&& ( pen == other.pen );
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtIntervalSymbol::Style style;
|
||||||
|
int width;
|
||||||
|
|
||||||
|
QPen pen;
|
||||||
|
QBrush brush;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
\param style Style of the symbol
|
||||||
|
\sa setStyle(), style(), Style
|
||||||
|
*/
|
||||||
|
QwtIntervalSymbol::QwtIntervalSymbol( Style style )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
d_data->style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Copy constructor
|
||||||
|
QwtIntervalSymbol::QwtIntervalSymbol( const QwtIntervalSymbol &other )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
*d_data = *other.d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtIntervalSymbol::~QwtIntervalSymbol()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \brief Assignment operator
|
||||||
|
QwtIntervalSymbol &QwtIntervalSymbol::operator=(
|
||||||
|
const QwtIntervalSymbol &other )
|
||||||
|
{
|
||||||
|
*d_data = *other.d_data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \brief Compare two symbols
|
||||||
|
bool QwtIntervalSymbol::operator==(
|
||||||
|
const QwtIntervalSymbol &other ) const
|
||||||
|
{
|
||||||
|
return *d_data == *other.d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \brief Compare two symbols
|
||||||
|
bool QwtIntervalSymbol::operator!=(
|
||||||
|
const QwtIntervalSymbol &other ) const
|
||||||
|
{
|
||||||
|
return !( *d_data == *other.d_data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Specify the symbol style
|
||||||
|
|
||||||
|
\param style Style
|
||||||
|
\sa style(), Style
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::setStyle( Style style )
|
||||||
|
{
|
||||||
|
d_data->style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Current symbol style
|
||||||
|
\sa setStyle()
|
||||||
|
*/
|
||||||
|
QwtIntervalSymbol::Style QwtIntervalSymbol::style() const
|
||||||
|
{
|
||||||
|
return d_data->style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Specify the width of the symbol
|
||||||
|
It is used depending on the style.
|
||||||
|
|
||||||
|
\param width Width
|
||||||
|
\sa width(), setStyle()
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::setWidth( int width )
|
||||||
|
{
|
||||||
|
d_data->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Width of the symbol.
|
||||||
|
\sa setWidth(), setStyle()
|
||||||
|
*/
|
||||||
|
int QwtIntervalSymbol::width() const
|
||||||
|
{
|
||||||
|
return d_data->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Assign a brush
|
||||||
|
|
||||||
|
The brush is used for the Box style.
|
||||||
|
|
||||||
|
\param brush Brush
|
||||||
|
\sa brush()
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::setBrush( const QBrush &brush )
|
||||||
|
{
|
||||||
|
d_data->brush = brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Brush
|
||||||
|
\sa setBrush()
|
||||||
|
*/
|
||||||
|
const QBrush& QwtIntervalSymbol::brush() const
|
||||||
|
{
|
||||||
|
return d_data->brush;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build and assign a pen
|
||||||
|
|
||||||
|
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||||
|
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||||
|
to hide this incompatibility.
|
||||||
|
|
||||||
|
\param color Pen color
|
||||||
|
\param width Pen width
|
||||||
|
\param style Pen style
|
||||||
|
|
||||||
|
\sa pen(), brush()
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::setPen( const QColor &color,
|
||||||
|
qreal width, Qt::PenStyle style )
|
||||||
|
{
|
||||||
|
setPen( QPen( color, width, style ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign a pen
|
||||||
|
|
||||||
|
\param pen Pen
|
||||||
|
\sa pen(), setBrush()
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::setPen( const QPen &pen )
|
||||||
|
{
|
||||||
|
d_data->pen = pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Pen
|
||||||
|
\sa setPen(), brush()
|
||||||
|
*/
|
||||||
|
const QPen& QwtIntervalSymbol::pen() const
|
||||||
|
{
|
||||||
|
return d_data->pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw a symbol depending on its style
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param orientation Orientation
|
||||||
|
\param from Start point of the interval in target device coordinates
|
||||||
|
\param to End point of the interval in target device coordinates
|
||||||
|
|
||||||
|
\sa setStyle()
|
||||||
|
*/
|
||||||
|
void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation,
|
||||||
|
const QPointF &from, const QPointF &to ) const
|
||||||
|
{
|
||||||
|
const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) );
|
||||||
|
|
||||||
|
QPointF p1 = from;
|
||||||
|
QPointF p2 = to;
|
||||||
|
if ( QwtPainter::roundingAlignment( painter ) )
|
||||||
|
{
|
||||||
|
p1 = p1.toPoint();
|
||||||
|
p2 = p2.toPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( d_data->style )
|
||||||
|
{
|
||||||
|
case QwtIntervalSymbol::Bar:
|
||||||
|
{
|
||||||
|
QwtPainter::drawLine( painter, p1, p2 );
|
||||||
|
if ( d_data->width > pw )
|
||||||
|
{
|
||||||
|
if ( ( orientation == Qt::Horizontal )
|
||||||
|
&& ( p1.y() == p2.y() ) )
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double y = p1.y() - sw / 2;
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
p1.x(), y, p1.x(), y + sw );
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
p2.x(), y, p2.x(), y + sw );
|
||||||
|
}
|
||||||
|
else if ( ( orientation == Qt::Vertical )
|
||||||
|
&& ( p1.x() == p2.x() ) )
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double x = p1.x() - sw / 2;
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
x, p1.y(), x + sw, p1.y() );
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
x, p2.y(), x + sw, p2.y() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double dx = p2.x() - p1.x();
|
||||||
|
const double dy = p2.y() - p1.y();
|
||||||
|
const double angle = qAtan2( dy, dx ) + M_PI_2;
|
||||||
|
double dw2 = sw / 2.0;
|
||||||
|
|
||||||
|
const double cx = qFastCos( angle ) * dw2;
|
||||||
|
const double sy = qFastSin( angle ) * dw2;
|
||||||
|
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
p1.x() - cx, p1.y() - sy,
|
||||||
|
p1.x() + cx, p1.y() + sy );
|
||||||
|
QwtPainter::drawLine( painter,
|
||||||
|
p2.x() - cx, p2.y() - sy,
|
||||||
|
p2.x() + cx, p2.y() + sy );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtIntervalSymbol::Box:
|
||||||
|
{
|
||||||
|
if ( d_data->width <= pw )
|
||||||
|
{
|
||||||
|
QwtPainter::drawLine( painter, p1, p2 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( ( orientation == Qt::Horizontal )
|
||||||
|
&& ( p1.y() == p2.y() ) )
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double y = p1.y() - d_data->width / 2;
|
||||||
|
QwtPainter::drawRect( painter,
|
||||||
|
p1.x(), y, p2.x() - p1.x(), sw );
|
||||||
|
}
|
||||||
|
else if ( ( orientation == Qt::Vertical )
|
||||||
|
&& ( p1.x() == p2.x() ) )
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double x = p1.x() - d_data->width / 2;
|
||||||
|
QwtPainter::drawRect( painter,
|
||||||
|
x, p1.y(), sw, p2.y() - p1.y() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double sw = d_data->width;
|
||||||
|
|
||||||
|
const double dx = p2.x() - p1.x();
|
||||||
|
const double dy = p2.y() - p1.y();
|
||||||
|
const double angle = qAtan2( dy, dx ) + M_PI_2;
|
||||||
|
double dw2 = sw / 2.0;
|
||||||
|
|
||||||
|
const double cx = qFastCos( angle ) * dw2;
|
||||||
|
const double sy = qFastSin( angle ) * dw2;
|
||||||
|
|
||||||
|
QPolygonF polygon;
|
||||||
|
polygon += QPointF( p1.x() - cx, p1.y() - sy );
|
||||||
|
polygon += QPointF( p1.x() + cx, p1.y() + sy );
|
||||||
|
polygon += QPointF( p2.x() + cx, p2.y() + sy );
|
||||||
|
polygon += QPointF( p2.x() - cx, p2.y() - sy );
|
||||||
|
|
||||||
|
QwtPainter::drawPolygon( painter, polygon );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_INTERVAL_SYMBOL_H
|
||||||
|
#define QWT_INTERVAL_SYMBOL_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpen.h>
|
||||||
|
#include <qsize.h>
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
class QRect;
|
||||||
|
class QPointF;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A drawing primitive for displaying an interval like an error bar
|
||||||
|
|
||||||
|
\sa QwtPlotIntervalCurve
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtIntervalSymbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Symbol style
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
//! No Style. The symbol cannot be drawn.
|
||||||
|
NoSymbol = -1,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The symbol displays a line with caps at the beginning/end.
|
||||||
|
The size of the caps depends on the symbol width().
|
||||||
|
*/
|
||||||
|
Bar,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The symbol displays a plain rectangle using pen() and brush().
|
||||||
|
The size of the rectangle depends on the translated interval and
|
||||||
|
the width(),
|
||||||
|
*/
|
||||||
|
Box,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Styles >= UserSymbol are reserved for derived
|
||||||
|
classes of QwtIntervalSymbol that overload draw() with
|
||||||
|
additional application specific symbol types.
|
||||||
|
*/
|
||||||
|
UserSymbol = 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
QwtIntervalSymbol( Style = NoSymbol );
|
||||||
|
QwtIntervalSymbol( const QwtIntervalSymbol & );
|
||||||
|
virtual ~QwtIntervalSymbol();
|
||||||
|
|
||||||
|
QwtIntervalSymbol &operator=( const QwtIntervalSymbol & );
|
||||||
|
bool operator==( const QwtIntervalSymbol & ) const;
|
||||||
|
bool operator!=( const QwtIntervalSymbol & ) const;
|
||||||
|
|
||||||
|
void setWidth( int );
|
||||||
|
int width() const;
|
||||||
|
|
||||||
|
void setBrush( const QBrush & );
|
||||||
|
const QBrush& brush() const;
|
||||||
|
|
||||||
|
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||||
|
void setPen( const QPen & );
|
||||||
|
const QPen& pen() const;
|
||||||
|
|
||||||
|
void setStyle( Style );
|
||||||
|
Style style() const;
|
||||||
|
|
||||||
|
virtual void draw( QPainter *, Qt::Orientation,
|
||||||
|
const QPointF& from, const QPointF& to ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData* d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,855 @@
|
|||||||
|
/* -*- 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 "qwt_knob.h"
|
||||||
|
#include "qwt_round_scale_draw.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_scale_map.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
#include <qstyleoption.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qmath.h>
|
||||||
|
#include <qapplication.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040601
|
||||||
|
#define qAtan2(y, x) ::atan2(y, x)
|
||||||
|
#define qFabs(x) ::fabs(x)
|
||||||
|
#define qFastCos(x) qCos(x)
|
||||||
|
#define qFastSin(x) qSin(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static QSize qwtKnobSizeHint( const QwtKnob *knob, int min )
|
||||||
|
{
|
||||||
|
int knobWidth = knob->knobWidth();
|
||||||
|
if ( knobWidth <= 0 )
|
||||||
|
knobWidth = qMax( 3 * knob->markerSize(), min );
|
||||||
|
|
||||||
|
// Add the scale radial thickness to the knobWidth
|
||||||
|
const int extent = qCeil( knob->scaleDraw()->extent( knob->font() ) );
|
||||||
|
const int d = 2 * ( extent + 4 ) + knobWidth;
|
||||||
|
|
||||||
|
int left, right, top, bottom;
|
||||||
|
knob->getContentsMargins( &left, &top, &right, &bottom );
|
||||||
|
|
||||||
|
return QSize( d + left + right, d + top + bottom );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double qwtToScaleAngle( double angle )
|
||||||
|
{
|
||||||
|
// the map is counter clockwise with the origin
|
||||||
|
// at 90° using angles from -180° -> 180°
|
||||||
|
|
||||||
|
double a = 90.0 - angle;
|
||||||
|
if ( a <= -180.0 )
|
||||||
|
a += 360.0;
|
||||||
|
else if ( a >= 180.0 )
|
||||||
|
a -= 360.0;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double qwtToDegrees( double value )
|
||||||
|
{
|
||||||
|
return qwtNormalizeDegrees( 90.0 - value );
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtKnob::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
knobStyle( QwtKnob::Raised ),
|
||||||
|
markerStyle( QwtKnob::Notch ),
|
||||||
|
borderWidth( 2 ),
|
||||||
|
borderDist( 4 ),
|
||||||
|
scaleDist( 4 ),
|
||||||
|
maxScaleTicks( 11 ),
|
||||||
|
knobWidth( 0 ),
|
||||||
|
alignment( Qt::AlignCenter ),
|
||||||
|
markerSize( 8 ),
|
||||||
|
totalAngle( 270.0 ),
|
||||||
|
mouseOffset( 0.0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtKnob::KnobStyle knobStyle;
|
||||||
|
QwtKnob::MarkerStyle markerStyle;
|
||||||
|
|
||||||
|
int borderWidth;
|
||||||
|
int borderDist;
|
||||||
|
int scaleDist;
|
||||||
|
int maxScaleTicks;
|
||||||
|
int knobWidth;
|
||||||
|
Qt::Alignment alignment;
|
||||||
|
int markerSize;
|
||||||
|
|
||||||
|
double totalAngle;
|
||||||
|
|
||||||
|
double mouseOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Constructor
|
||||||
|
|
||||||
|
Construct a knob with an angle of 270°. The style is
|
||||||
|
QwtKnob::Raised and the marker style is QwtKnob::Notch.
|
||||||
|
The width of the knob is set to 50 pixels.
|
||||||
|
|
||||||
|
\param parent Parent widget
|
||||||
|
|
||||||
|
\sa setTotalAngle()
|
||||||
|
*/
|
||||||
|
QwtKnob::QwtKnob( QWidget* parent ):
|
||||||
|
QwtAbstractSlider( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
|
||||||
|
setScaleDraw( new QwtRoundScaleDraw() );
|
||||||
|
|
||||||
|
setTotalAngle( 270.0 );
|
||||||
|
|
||||||
|
setScale( 0.0, 10.0 );
|
||||||
|
setValue( 0.0 );
|
||||||
|
|
||||||
|
setSizePolicy( QSizePolicy::MinimumExpanding,
|
||||||
|
QSizePolicy::MinimumExpanding );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtKnob::~QwtKnob()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the knob type
|
||||||
|
|
||||||
|
\param knobStyle Knob type
|
||||||
|
\sa knobStyle(), setBorderWidth()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setKnobStyle( KnobStyle knobStyle )
|
||||||
|
{
|
||||||
|
if ( d_data->knobStyle != knobStyle )
|
||||||
|
{
|
||||||
|
d_data->knobStyle = knobStyle;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Marker type of the knob
|
||||||
|
\sa setKnobStyle(), setBorderWidth()
|
||||||
|
*/
|
||||||
|
QwtKnob::KnobStyle QwtKnob::knobStyle() const
|
||||||
|
{
|
||||||
|
return d_data->knobStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the marker type of the knob
|
||||||
|
|
||||||
|
\param markerStyle Marker type
|
||||||
|
\sa markerStyle(), setMarkerSize()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setMarkerStyle( MarkerStyle markerStyle )
|
||||||
|
{
|
||||||
|
if ( d_data->markerStyle != markerStyle )
|
||||||
|
{
|
||||||
|
d_data->markerStyle = markerStyle;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Marker type of the knob
|
||||||
|
\sa setMarkerStyle(), setMarkerSize()
|
||||||
|
*/
|
||||||
|
QwtKnob::MarkerStyle QwtKnob::markerStyle() const
|
||||||
|
{
|
||||||
|
return d_data->markerStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the total angle by which the knob can be turned
|
||||||
|
\param angle Angle in degrees.
|
||||||
|
|
||||||
|
The angle has to be between [10, 360] degrees. Angles above
|
||||||
|
360 ( so that the knob can be turned several times around its axis )
|
||||||
|
have to be set using setNumTurns().
|
||||||
|
|
||||||
|
The default angle is 270 degrees.
|
||||||
|
|
||||||
|
\sa totalAngle(), setNumTurns()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setTotalAngle ( double angle )
|
||||||
|
{
|
||||||
|
angle = qBound( 10.0, angle, 360.0 );
|
||||||
|
|
||||||
|
if ( angle != d_data->totalAngle )
|
||||||
|
{
|
||||||
|
d_data->totalAngle = angle;
|
||||||
|
|
||||||
|
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
|
||||||
|
0.5 * d_data->totalAngle );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the total angle
|
||||||
|
\sa setTotalAngle(), setNumTurns(), numTurns()
|
||||||
|
*/
|
||||||
|
double QwtKnob::totalAngle() const
|
||||||
|
{
|
||||||
|
return d_data->totalAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the number of turns
|
||||||
|
|
||||||
|
When numTurns > 1 the knob can be turned several times around its axis
|
||||||
|
- otherwise the total angle is floored to 360°.
|
||||||
|
|
||||||
|
\sa numTurns(), totalAngle(), setTotalAngle()
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QwtKnob::setNumTurns( int numTurns )
|
||||||
|
{
|
||||||
|
numTurns = qMax( numTurns, 1 );
|
||||||
|
|
||||||
|
if ( numTurns == 1 && d_data->totalAngle <= 360.0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const double angle = numTurns * 360.0;
|
||||||
|
if ( angle != d_data->totalAngle )
|
||||||
|
{
|
||||||
|
d_data->totalAngle = angle;
|
||||||
|
|
||||||
|
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
|
||||||
|
0.5 * d_data->totalAngle );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of turns.
|
||||||
|
|
||||||
|
When the total angle is below 360° numTurns() is ceiled to 1.
|
||||||
|
\sa setNumTurns(), setTotalAngle(), totalAngle()
|
||||||
|
*/
|
||||||
|
int QwtKnob::numTurns() const
|
||||||
|
{
|
||||||
|
return qCeil( d_data->totalAngle / 360.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the scale draw of the knob
|
||||||
|
|
||||||
|
For changing the labels of the scales, it
|
||||||
|
is necessary to derive from QwtRoundScaleDraw and
|
||||||
|
overload QwtRoundScaleDraw::label().
|
||||||
|
|
||||||
|
\sa scaleDraw()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
|
||||||
|
{
|
||||||
|
setAbstractScaleDraw( scaleDraw );
|
||||||
|
setTotalAngle( d_data->totalAngle );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the scale draw of the knob
|
||||||
|
\sa setScaleDraw()
|
||||||
|
*/
|
||||||
|
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
|
||||||
|
{
|
||||||
|
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the scale draw of the knob
|
||||||
|
\sa setScaleDraw()
|
||||||
|
*/
|
||||||
|
QwtRoundScaleDraw *QwtKnob::scaleDraw()
|
||||||
|
{
|
||||||
|
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Calculate the bounding rectangle of the knob without the scale
|
||||||
|
|
||||||
|
\return Bounding rectangle of the knob
|
||||||
|
\sa knobWidth(), alignment(), QWidget::contentsRect()
|
||||||
|
*/
|
||||||
|
QRect QwtKnob::knobRect() const
|
||||||
|
{
|
||||||
|
const QRect cr = contentsRect();
|
||||||
|
|
||||||
|
const int extent = qCeil( scaleDraw()->extent( font() ) );
|
||||||
|
const int d = extent + d_data->scaleDist;
|
||||||
|
|
||||||
|
int w = d_data->knobWidth;
|
||||||
|
if ( w <= 0 )
|
||||||
|
{
|
||||||
|
const int dim = qMin( cr.width(), cr.height() );
|
||||||
|
|
||||||
|
w = dim - 2 * ( d );
|
||||||
|
w = qMax( 0, w );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect r( 0, 0, w, w );
|
||||||
|
|
||||||
|
if ( d_data->alignment & Qt::AlignLeft )
|
||||||
|
{
|
||||||
|
r.moveLeft( cr.left() + d );
|
||||||
|
}
|
||||||
|
else if ( d_data->alignment & Qt::AlignRight )
|
||||||
|
{
|
||||||
|
r.moveRight( cr.right() - d );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.moveCenter( QPoint( cr.center().x(), r.center().y() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->alignment & Qt::AlignTop )
|
||||||
|
{
|
||||||
|
r.moveTop( cr.top() + d );
|
||||||
|
}
|
||||||
|
else if ( d_data->alignment & Qt::AlignBottom )
|
||||||
|
{
|
||||||
|
r.moveBottom( cr.bottom() - d );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.moveCenter( QPoint( r.center().x(), cr.center().y() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine what to do when the user presses a mouse button.
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\retval True, when pos is inside the circle of the knob.
|
||||||
|
\sa scrolledTo()
|
||||||
|
*/
|
||||||
|
bool QwtKnob::isScrollPosition( const QPoint &pos ) const
|
||||||
|
{
|
||||||
|
const QRect kr = knobRect();
|
||||||
|
|
||||||
|
const QRegion region( kr, QRegion::Ellipse );
|
||||||
|
if ( region.contains( pos ) && ( pos != kr.center() ) )
|
||||||
|
{
|
||||||
|
const double angle = QLineF( kr.center(), pos ).angle();
|
||||||
|
const double valueAngle = qwtToDegrees( scaleMap().transform( value() ) );
|
||||||
|
|
||||||
|
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Determine the value for a new position of the mouse
|
||||||
|
|
||||||
|
\param pos Mouse position
|
||||||
|
|
||||||
|
\return Value for the mouse position
|
||||||
|
\sa isScrollPosition()
|
||||||
|
*/
|
||||||
|
double QwtKnob::scrolledTo( const QPoint &pos ) const
|
||||||
|
{
|
||||||
|
double angle = QLineF( rect().center(), pos ).angle();
|
||||||
|
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
|
||||||
|
|
||||||
|
if ( scaleMap().pDist() > 360.0 )
|
||||||
|
{
|
||||||
|
angle = qwtToDegrees( angle );
|
||||||
|
|
||||||
|
const double v = scaleMap().transform( value() );
|
||||||
|
|
||||||
|
int numTurns = qFloor( ( v - scaleMap().p1() ) / 360.0 );
|
||||||
|
|
||||||
|
double valueAngle = qwtNormalizeDegrees( v );
|
||||||
|
if ( qAbs( valueAngle - angle ) > 180.0 )
|
||||||
|
{
|
||||||
|
numTurns += ( angle > valueAngle ) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
angle += scaleMap().p1() + numTurns * 360.0;
|
||||||
|
|
||||||
|
if ( !wrapping() )
|
||||||
|
{
|
||||||
|
const double boundedAngle =
|
||||||
|
qBound( scaleMap().p1(), angle, scaleMap().p2() );
|
||||||
|
|
||||||
|
d_data->mouseOffset += ( boundedAngle - angle );
|
||||||
|
angle = boundedAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angle = qwtToScaleAngle( angle );
|
||||||
|
|
||||||
|
double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() );
|
||||||
|
|
||||||
|
if ( !wrapping() )
|
||||||
|
{
|
||||||
|
const double currentAngle = scaleMap().transform( value() );
|
||||||
|
|
||||||
|
if ( ( currentAngle > 90.0 ) && ( boundedAngle < -90.0 ) )
|
||||||
|
boundedAngle = scaleMap().p2();
|
||||||
|
else if ( ( currentAngle < -90.0 ) && ( boundedAngle > 90.0 ) )
|
||||||
|
boundedAngle = scaleMap().p1();
|
||||||
|
|
||||||
|
d_data->mouseOffset += ( boundedAngle - angle );
|
||||||
|
}
|
||||||
|
|
||||||
|
angle = boundedAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scaleMap().invTransform( angle );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle QEvent::StyleChange and QEvent::FontChange;
|
||||||
|
\param event Change event
|
||||||
|
*/
|
||||||
|
void QwtKnob::changeEvent( QEvent *event )
|
||||||
|
{
|
||||||
|
switch( event->type() )
|
||||||
|
{
|
||||||
|
case QEvent::StyleChange:
|
||||||
|
case QEvent::FontChange:
|
||||||
|
{
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Repaint the knob
|
||||||
|
\param event Paint event
|
||||||
|
*/
|
||||||
|
void QwtKnob::paintEvent( QPaintEvent *event )
|
||||||
|
{
|
||||||
|
const QRectF knobRect = this->knobRect();
|
||||||
|
|
||||||
|
QPainter painter( this );
|
||||||
|
painter.setClipRegion( event->region() );
|
||||||
|
|
||||||
|
QStyleOption opt;
|
||||||
|
opt.init(this);
|
||||||
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||||
|
|
||||||
|
painter.setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
|
||||||
|
if ( !knobRect.contains( event->region().boundingRect() ) )
|
||||||
|
{
|
||||||
|
scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist );
|
||||||
|
scaleDraw()->moveCenter( knobRect.center() );
|
||||||
|
|
||||||
|
scaleDraw()->draw( &painter, palette() );
|
||||||
|
}
|
||||||
|
|
||||||
|
drawKnob( &painter, knobRect );
|
||||||
|
|
||||||
|
drawMarker( &painter, knobRect,
|
||||||
|
qwtNormalizeDegrees( scaleMap().transform( value() ) ) );
|
||||||
|
|
||||||
|
painter.setRenderHint( QPainter::Antialiasing, false );
|
||||||
|
|
||||||
|
if ( hasFocus() )
|
||||||
|
drawFocusIndicator( &painter );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the knob
|
||||||
|
|
||||||
|
\param painter painter
|
||||||
|
\param knobRect Bounding rectangle of the knob (without scale)
|
||||||
|
*/
|
||||||
|
void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const
|
||||||
|
{
|
||||||
|
double dim = qMin( knobRect.width(), knobRect.height() );
|
||||||
|
dim -= d_data->borderWidth * 0.5;
|
||||||
|
|
||||||
|
QRectF aRect( 0, 0, dim, dim );
|
||||||
|
aRect.moveCenter( knobRect.center() );
|
||||||
|
|
||||||
|
QPen pen( Qt::NoPen );
|
||||||
|
if ( d_data->borderWidth > 0 )
|
||||||
|
{
|
||||||
|
QColor c1 = palette().color( QPalette::Light );
|
||||||
|
QColor c2 = palette().color( QPalette::Dark );
|
||||||
|
|
||||||
|
QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() );
|
||||||
|
gradient.setColorAt( 0.0, c1 );
|
||||||
|
gradient.setColorAt( 0.3, c1 );
|
||||||
|
gradient.setColorAt( 0.7, c2 );
|
||||||
|
gradient.setColorAt( 1.0, c2 );
|
||||||
|
|
||||||
|
pen = QPen( gradient, d_data->borderWidth );
|
||||||
|
}
|
||||||
|
|
||||||
|
QBrush brush;
|
||||||
|
switch( d_data->knobStyle )
|
||||||
|
{
|
||||||
|
case QwtKnob::Raised:
|
||||||
|
{
|
||||||
|
double off = 0.3 * knobRect.width();
|
||||||
|
QRadialGradient gradient( knobRect.center(),
|
||||||
|
knobRect.width(), knobRect.topLeft() + QPointF( off, off ) );
|
||||||
|
|
||||||
|
gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) );
|
||||||
|
gradient.setColorAt( 1.0, palette().color( QPalette::Button ) );
|
||||||
|
|
||||||
|
brush = QBrush( gradient );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtKnob::Styled:
|
||||||
|
{
|
||||||
|
QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3,
|
||||||
|
knobRect.center().y() - knobRect.height() / 2,
|
||||||
|
knobRect.width() * 1.3,
|
||||||
|
knobRect.center().x(),
|
||||||
|
knobRect.center().y() - knobRect.height() / 2);
|
||||||
|
|
||||||
|
const QColor c = palette().color( QPalette::Button );
|
||||||
|
gradient.setColorAt(0, c.lighter(110));
|
||||||
|
gradient.setColorAt(qreal(0.5), c);
|
||||||
|
gradient.setColorAt(qreal(0.501), c.darker(102));
|
||||||
|
gradient.setColorAt(1, c.darker(115));
|
||||||
|
|
||||||
|
brush = QBrush( gradient );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtKnob::Sunken:
|
||||||
|
{
|
||||||
|
QLinearGradient gradient(
|
||||||
|
knobRect.topLeft(), knobRect.bottomRight() );
|
||||||
|
gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) );
|
||||||
|
gradient.setColorAt( 0.5, palette().color( QPalette::Button ) );
|
||||||
|
gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) );
|
||||||
|
brush = QBrush( gradient );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QwtKnob::Flat:
|
||||||
|
default:
|
||||||
|
brush = palette().brush( QPalette::Button );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( brush );
|
||||||
|
painter->drawEllipse( aRect );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Draw the marker at the knob's front
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param rect Bounding rectangle of the knob without scale
|
||||||
|
\param angle Angle of the marker in degrees
|
||||||
|
( clockwise, 0 at the 12 o'clock position )
|
||||||
|
*/
|
||||||
|
void QwtKnob::drawMarker( QPainter *painter,
|
||||||
|
const QRectF &rect, double angle ) const
|
||||||
|
{
|
||||||
|
if ( d_data->markerStyle == NoMarker || !isValid() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const double radians = qwtRadians( angle );
|
||||||
|
const double sinA = -qFastSin( radians );
|
||||||
|
const double cosA = qFastCos( radians );
|
||||||
|
|
||||||
|
const double xm = rect.center().x();
|
||||||
|
const double ym = rect.center().y();
|
||||||
|
const double margin = 4.0;
|
||||||
|
|
||||||
|
double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
|
||||||
|
if ( radius < 1.0 )
|
||||||
|
radius = 1.0;
|
||||||
|
|
||||||
|
int markerSize = d_data->markerSize;
|
||||||
|
if ( markerSize <= 0 )
|
||||||
|
markerSize = qRound( 0.4 * radius );
|
||||||
|
|
||||||
|
switch ( d_data->markerStyle )
|
||||||
|
{
|
||||||
|
case Notch:
|
||||||
|
case Nub:
|
||||||
|
{
|
||||||
|
const double dotWidth =
|
||||||
|
qMin( double( markerSize ), radius);
|
||||||
|
|
||||||
|
const double dotCenterDist = radius - 0.5 * dotWidth;
|
||||||
|
if ( dotCenterDist > 0.0 )
|
||||||
|
{
|
||||||
|
const QPointF center( xm - sinA * dotCenterDist,
|
||||||
|
ym - cosA * dotCenterDist );
|
||||||
|
|
||||||
|
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
|
||||||
|
ellipse.moveCenter( center );
|
||||||
|
|
||||||
|
QColor c1 = palette().color( QPalette::Light );
|
||||||
|
QColor c2 = palette().color( QPalette::Mid );
|
||||||
|
|
||||||
|
if ( d_data->markerStyle == Notch )
|
||||||
|
qSwap( c1, c2 );
|
||||||
|
|
||||||
|
QLinearGradient gradient(
|
||||||
|
ellipse.topLeft(), ellipse.bottomRight() );
|
||||||
|
gradient.setColorAt( 0.0, c1 );
|
||||||
|
gradient.setColorAt( 1.0, c2 );
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( gradient );
|
||||||
|
|
||||||
|
painter->drawEllipse( ellipse );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Dot:
|
||||||
|
{
|
||||||
|
const double dotWidth =
|
||||||
|
qMin( double( markerSize ), radius);
|
||||||
|
|
||||||
|
const double dotCenterDist = radius - 0.5 * dotWidth;
|
||||||
|
if ( dotCenterDist > 0.0 )
|
||||||
|
{
|
||||||
|
const QPointF center( xm - sinA * dotCenterDist,
|
||||||
|
ym - cosA * dotCenterDist );
|
||||||
|
|
||||||
|
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
|
||||||
|
ellipse.moveCenter( center );
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( palette().color( QPalette::ButtonText ) );
|
||||||
|
painter->drawEllipse( ellipse );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Tick:
|
||||||
|
{
|
||||||
|
const double rb = qMax( radius - markerSize, 1.0 );
|
||||||
|
const double re = radius;
|
||||||
|
|
||||||
|
const QLineF line( xm - sinA * rb, ym - cosA * rb,
|
||||||
|
xm - sinA * re, ym - cosA * re );
|
||||||
|
|
||||||
|
QPen pen( palette().color( QPalette::ButtonText ), 0 );
|
||||||
|
pen.setCapStyle( Qt::FlatCap );
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->drawLine ( line );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Triangle:
|
||||||
|
{
|
||||||
|
const double rb = qMax( radius - markerSize, 1.0 );
|
||||||
|
const double re = radius;
|
||||||
|
|
||||||
|
painter->translate( rect.center() );
|
||||||
|
painter->rotate( angle - 90.0 );
|
||||||
|
|
||||||
|
QPolygonF polygon;
|
||||||
|
polygon += QPointF( re, 0.0 );
|
||||||
|
polygon += QPointF( rb, 0.5 * ( re - rb ) );
|
||||||
|
polygon += QPointF( rb, -0.5 * ( re - rb ) );
|
||||||
|
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( palette().color( QPalette::ButtonText ) );
|
||||||
|
painter->drawPolygon( polygon );
|
||||||
|
|
||||||
|
painter->resetTransform();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw the focus indicator
|
||||||
|
\param painter Painter
|
||||||
|
*/
|
||||||
|
void QwtKnob::drawFocusIndicator( QPainter *painter ) const
|
||||||
|
{
|
||||||
|
const QRect cr = contentsRect();
|
||||||
|
|
||||||
|
int w = d_data->knobWidth;
|
||||||
|
if ( w <= 0 )
|
||||||
|
{
|
||||||
|
w = qMin( cr.width(), cr.height() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int extent = qCeil( scaleDraw()->extent( font() ) );
|
||||||
|
w += 2 * ( extent + d_data->scaleDist );
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect focusRect( 0, 0, w, w );
|
||||||
|
focusRect.moveCenter( cr.center() );
|
||||||
|
|
||||||
|
QwtPainter::drawFocusRect( painter, this, focusRect );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the alignment of the knob
|
||||||
|
|
||||||
|
Similar to a QLabel::alignment() the flags decide how
|
||||||
|
to align the knob inside of contentsRect().
|
||||||
|
|
||||||
|
The default setting is Qt::AlignCenter
|
||||||
|
|
||||||
|
\param alignment Or'd alignment flags
|
||||||
|
|
||||||
|
\sa alignment(), setKnobWidth(), knobRect()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setAlignment( Qt::Alignment alignment )
|
||||||
|
{
|
||||||
|
if ( d_data->alignment != alignment )
|
||||||
|
{
|
||||||
|
d_data->alignment = alignment;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Alignment of the knob inside of contentsRect()
|
||||||
|
\sa setAlignment(), knobWidth(), knobRect()
|
||||||
|
*/
|
||||||
|
Qt::Alignment QwtKnob::alignment() const
|
||||||
|
{
|
||||||
|
return d_data->alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the knob's width.
|
||||||
|
|
||||||
|
Setting a fixed value for the diameter of the knob
|
||||||
|
is helpful for aligning several knobs in a row.
|
||||||
|
|
||||||
|
\param width New width
|
||||||
|
|
||||||
|
\sa knobWidth(), setAlignment()
|
||||||
|
\note Modifies the sizePolicy()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setKnobWidth( int width )
|
||||||
|
{
|
||||||
|
width = qMax( width, 0 );
|
||||||
|
|
||||||
|
if ( width != d_data->knobWidth )
|
||||||
|
{
|
||||||
|
QSizePolicy::Policy policy;
|
||||||
|
if ( width > 0 )
|
||||||
|
policy = QSizePolicy::Minimum;
|
||||||
|
else
|
||||||
|
policy = QSizePolicy::MinimumExpanding;
|
||||||
|
|
||||||
|
setSizePolicy( policy, policy );
|
||||||
|
|
||||||
|
d_data->knobWidth = width;
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return the width of the knob
|
||||||
|
int QwtKnob::knobWidth() const
|
||||||
|
{
|
||||||
|
return d_data->knobWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the knob's border width
|
||||||
|
\param borderWidth new border width
|
||||||
|
*/
|
||||||
|
void QwtKnob::setBorderWidth( int borderWidth )
|
||||||
|
{
|
||||||
|
d_data->borderWidth = qMax( borderWidth, 0 );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return the border width
|
||||||
|
int QwtKnob::borderWidth() const
|
||||||
|
{
|
||||||
|
return d_data->borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the size of the marker
|
||||||
|
|
||||||
|
When setting a size <= 0 the marker will
|
||||||
|
automatically scaled to 40% of the radius of the knob.
|
||||||
|
|
||||||
|
\sa markerSize(), markerStyle()
|
||||||
|
*/
|
||||||
|
void QwtKnob::setMarkerSize( int size )
|
||||||
|
{
|
||||||
|
if ( d_data->markerSize != size )
|
||||||
|
{
|
||||||
|
d_data->markerSize = size;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Marker size
|
||||||
|
\sa setMarkerSize()
|
||||||
|
*/
|
||||||
|
int QwtKnob::markerSize() const
|
||||||
|
{
|
||||||
|
return d_data->markerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return sizeHint()
|
||||||
|
*/
|
||||||
|
QSize QwtKnob::sizeHint() const
|
||||||
|
{
|
||||||
|
const QSize hint = qwtKnobSizeHint( this, 50 );
|
||||||
|
return hint.expandedTo( QApplication::globalStrut() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Minimum size hint
|
||||||
|
\sa sizeHint()
|
||||||
|
*/
|
||||||
|
QSize QwtKnob::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
return qwtKnobSizeHint( this, 20 );
|
||||||
|
}
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_KNOB_H
|
||||||
|
#define QWT_KNOB_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_abstract_slider.h"
|
||||||
|
|
||||||
|
class QwtRoundScaleDraw;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The Knob Widget
|
||||||
|
|
||||||
|
The QwtKnob widget imitates look and behavior of a volume knob on a radio.
|
||||||
|
It looks similar to QDial - not to QwtDial.
|
||||||
|
|
||||||
|
The value range of a knob might be divided into several turns.
|
||||||
|
|
||||||
|
The layout of the knob depends on the knobWidth().
|
||||||
|
|
||||||
|
- width > 0
|
||||||
|
The diameter of the knob is fixed and the knob is aligned
|
||||||
|
according to the alignment() flags inside of the contentsRect().
|
||||||
|
|
||||||
|
- width <= 0
|
||||||
|
The knob is extended to the minimum of width/height of the contentsRect()
|
||||||
|
and aligned in the other direction according to alignment().
|
||||||
|
|
||||||
|
Setting a fixed knobWidth() is helpful to align several knobs with different
|
||||||
|
scale labels.
|
||||||
|
|
||||||
|
\image html knob.png
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtKnob: public QwtAbstractSlider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_ENUMS ( KnobStyle MarkerStyle )
|
||||||
|
|
||||||
|
Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle )
|
||||||
|
Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth )
|
||||||
|
Q_PROPERTY( Qt::Alignment alignment READ alignment WRITE setAlignment )
|
||||||
|
Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle )
|
||||||
|
Q_PROPERTY( int numTurns READ numTurns WRITE setNumTurns )
|
||||||
|
Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle )
|
||||||
|
Q_PROPERTY( int markerSize READ markerSize WRITE setMarkerSize )
|
||||||
|
Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
\brief Style of the knob surface
|
||||||
|
|
||||||
|
Depending on the KnobStyle the surface of the knob is
|
||||||
|
filled from the brushes of the widget palette().
|
||||||
|
|
||||||
|
\sa setKnobStyle(), knobStyle()
|
||||||
|
*/
|
||||||
|
enum KnobStyle
|
||||||
|
{
|
||||||
|
//! Fill the knob with a brush from QPalette::Button.
|
||||||
|
Flat,
|
||||||
|
|
||||||
|
//! Build a gradient from QPalette::Midlight and QPalette::Button
|
||||||
|
Raised,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build a gradient from QPalette::Midlight, QPalette::Button
|
||||||
|
and QPalette::Midlight
|
||||||
|
*/
|
||||||
|
Sunken,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Build a radial gradient from QPalette::Button
|
||||||
|
like it is used for QDial in various Qt styles.
|
||||||
|
*/
|
||||||
|
Styled
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Marker type
|
||||||
|
|
||||||
|
The marker indicates the current value on the knob
|
||||||
|
The default setting is a Notch marker.
|
||||||
|
|
||||||
|
\sa setMarkerStyle(), setMarkerSize()
|
||||||
|
*/
|
||||||
|
enum MarkerStyle
|
||||||
|
{
|
||||||
|
//! Don't paint any marker
|
||||||
|
NoMarker = -1,
|
||||||
|
|
||||||
|
//! Paint a single tick in QPalette::ButtonText color
|
||||||
|
Tick,
|
||||||
|
|
||||||
|
//! Paint a triangle in QPalette::ButtonText color
|
||||||
|
Triangle,
|
||||||
|
|
||||||
|
//! Paint a circle in QPalette::ButtonText color
|
||||||
|
Dot,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw a raised ellipse with a gradient build from
|
||||||
|
QPalette::Light and QPalette::Mid
|
||||||
|
*/
|
||||||
|
Nub,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw a sunken ellipse with a gradient build from
|
||||||
|
QPalette::Light and QPalette::Mid
|
||||||
|
*/
|
||||||
|
Notch
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit QwtKnob( QWidget* parent = NULL );
|
||||||
|
virtual ~QwtKnob();
|
||||||
|
|
||||||
|
void setAlignment( Qt::Alignment );
|
||||||
|
Qt::Alignment alignment() const;
|
||||||
|
|
||||||
|
void setKnobWidth( int );
|
||||||
|
int knobWidth() const;
|
||||||
|
|
||||||
|
void setNumTurns( int );
|
||||||
|
int numTurns() const;
|
||||||
|
|
||||||
|
void setTotalAngle ( double angle );
|
||||||
|
double totalAngle() const;
|
||||||
|
|
||||||
|
void setKnobStyle( KnobStyle );
|
||||||
|
KnobStyle knobStyle() const;
|
||||||
|
|
||||||
|
void setBorderWidth( int );
|
||||||
|
int borderWidth() const;
|
||||||
|
|
||||||
|
void setMarkerStyle( MarkerStyle );
|
||||||
|
MarkerStyle markerStyle() const;
|
||||||
|
|
||||||
|
void setMarkerSize( int );
|
||||||
|
int markerSize() const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
virtual QSize minimumSizeHint() const;
|
||||||
|
|
||||||
|
void setScaleDraw( QwtRoundScaleDraw * );
|
||||||
|
|
||||||
|
const QwtRoundScaleDraw *scaleDraw() const;
|
||||||
|
QwtRoundScaleDraw *scaleDraw();
|
||||||
|
|
||||||
|
QRect knobRect() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent( QPaintEvent * );
|
||||||
|
virtual void changeEvent( QEvent * );
|
||||||
|
|
||||||
|
virtual void drawKnob( QPainter *, const QRectF & ) const;
|
||||||
|
|
||||||
|
virtual void drawFocusIndicator( QPainter * ) const;
|
||||||
|
|
||||||
|
virtual void drawMarker( QPainter *,
|
||||||
|
const QRectF &, double angle ) const;
|
||||||
|
|
||||||
|
virtual double scrolledTo( const QPoint & ) const;
|
||||||
|
virtual bool isScrollPosition( const QPoint & ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,827 @@
|
|||||||
|
/* -*- 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 "qwt_legend.h"
|
||||||
|
#include "qwt_legend_label.h"
|
||||||
|
#include "qwt_dyngrid_layout.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_plot_item.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include <qapplication.h>
|
||||||
|
#include <qscrollbar.h>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
#include <qstyleoption.h>
|
||||||
|
|
||||||
|
class QwtLegendMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline bool isEmpty() const { return d_entries.isEmpty(); }
|
||||||
|
|
||||||
|
void insert( const QVariant &, const QList<QWidget *> & );
|
||||||
|
void remove( const QVariant & );
|
||||||
|
|
||||||
|
void removeWidget( const QWidget * );
|
||||||
|
|
||||||
|
QList<QWidget *> legendWidgets( const QVariant & ) const;
|
||||||
|
QVariant itemInfo( const QWidget * ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// we don't know anything about itemInfo and therefore don't have
|
||||||
|
// any key that can be used for a map or hashtab.
|
||||||
|
// But a simple linear list is o.k. here, as we will never have
|
||||||
|
// more than a few entries.
|
||||||
|
|
||||||
|
class Entry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QVariant itemInfo;
|
||||||
|
QList<QWidget *> widgets;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList< Entry > d_entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
void QwtLegendMap::insert( const QVariant &itemInfo,
|
||||||
|
const QList<QWidget *> &widgets )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < d_entries.size(); i++ )
|
||||||
|
{
|
||||||
|
Entry &entry = d_entries[i];
|
||||||
|
if ( entry.itemInfo == itemInfo )
|
||||||
|
{
|
||||||
|
entry.widgets = widgets;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry newEntry;
|
||||||
|
newEntry.itemInfo = itemInfo;
|
||||||
|
newEntry.widgets = widgets;
|
||||||
|
|
||||||
|
d_entries += newEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtLegendMap::remove( const QVariant &itemInfo )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < d_entries.size(); i++ )
|
||||||
|
{
|
||||||
|
Entry &entry = d_entries[i];
|
||||||
|
if ( entry.itemInfo == itemInfo )
|
||||||
|
{
|
||||||
|
d_entries.removeAt( i );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtLegendMap::removeWidget( const QWidget *widget )
|
||||||
|
{
|
||||||
|
QWidget *w = const_cast<QWidget *>( widget );
|
||||||
|
|
||||||
|
for ( int i = 0; i < d_entries.size(); i++ )
|
||||||
|
d_entries[ i ].widgets.removeAll( w );
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const
|
||||||
|
{
|
||||||
|
if ( widget != NULL )
|
||||||
|
{
|
||||||
|
QWidget *w = const_cast<QWidget *>( widget );
|
||||||
|
|
||||||
|
for ( int i = 0; i < d_entries.size(); i++ )
|
||||||
|
{
|
||||||
|
const Entry &entry = d_entries[i];
|
||||||
|
if ( entry.widgets.indexOf( w ) >= 0 )
|
||||||
|
return entry.itemInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QWidget *> QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const
|
||||||
|
{
|
||||||
|
if ( itemInfo.isValid() )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < d_entries.size(); i++ )
|
||||||
|
{
|
||||||
|
const Entry &entry = d_entries[i];
|
||||||
|
if ( entry.itemInfo == itemInfo )
|
||||||
|
return entry.widgets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QList<QWidget *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtLegend::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
itemMode( QwtLegendData::ReadOnly ),
|
||||||
|
view( NULL )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtLegendData::Mode itemMode;
|
||||||
|
QwtLegendMap itemMap;
|
||||||
|
|
||||||
|
class LegendView;
|
||||||
|
LegendView *view;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QwtLegend::PrivateData::LegendView: public QScrollArea
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LegendView( QWidget *parent ):
|
||||||
|
QScrollArea( parent )
|
||||||
|
{
|
||||||
|
contentsWidget = new QWidget( this );
|
||||||
|
contentsWidget->setObjectName( "QwtLegendViewContents" );
|
||||||
|
|
||||||
|
setWidget( contentsWidget );
|
||||||
|
setWidgetResizable( false );
|
||||||
|
|
||||||
|
viewport()->setObjectName( "QwtLegendViewport" );
|
||||||
|
|
||||||
|
// QScrollArea::setWidget internally sets autoFillBackground to true
|
||||||
|
// But we don't want a background.
|
||||||
|
contentsWidget->setAutoFillBackground( false );
|
||||||
|
viewport()->setAutoFillBackground( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool event( QEvent *event )
|
||||||
|
{
|
||||||
|
if ( event->type() == QEvent::PolishRequest )
|
||||||
|
{
|
||||||
|
setFocusPolicy( Qt::NoFocus );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( event->type() == QEvent::Resize )
|
||||||
|
{
|
||||||
|
// adjust the size to en/disable the scrollbars
|
||||||
|
// before QScrollArea adjusts the viewport size
|
||||||
|
|
||||||
|
const QRect cr = contentsRect();
|
||||||
|
|
||||||
|
int w = cr.width();
|
||||||
|
int h = contentsWidget->heightForWidth( cr.width() );
|
||||||
|
if ( h > w )
|
||||||
|
{
|
||||||
|
w -= verticalScrollBar()->sizeHint().width();
|
||||||
|
h = contentsWidget->heightForWidth( w );
|
||||||
|
}
|
||||||
|
|
||||||
|
contentsWidget->resize( w, h );
|
||||||
|
}
|
||||||
|
|
||||||
|
return QScrollArea::event( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool viewportEvent( QEvent *event )
|
||||||
|
{
|
||||||
|
bool ok = QScrollArea::viewportEvent( event );
|
||||||
|
|
||||||
|
if ( event->type() == QEvent::Resize )
|
||||||
|
{
|
||||||
|
layoutContents();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize viewportSize( int w, int h ) const
|
||||||
|
{
|
||||||
|
const int sbHeight = horizontalScrollBar()->sizeHint().height();
|
||||||
|
const int sbWidth = verticalScrollBar()->sizeHint().width();
|
||||||
|
|
||||||
|
const int cw = contentsRect().width();
|
||||||
|
const int ch = contentsRect().height();
|
||||||
|
|
||||||
|
int vw = cw;
|
||||||
|
int vh = ch;
|
||||||
|
|
||||||
|
if ( w > vw )
|
||||||
|
vh -= sbHeight;
|
||||||
|
|
||||||
|
if ( h > vh )
|
||||||
|
{
|
||||||
|
vw -= sbWidth;
|
||||||
|
if ( w > vw && vh == ch )
|
||||||
|
vh -= sbHeight;
|
||||||
|
}
|
||||||
|
return QSize( vw, vh );
|
||||||
|
}
|
||||||
|
|
||||||
|
void layoutContents()
|
||||||
|
{
|
||||||
|
const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||||
|
contentsWidget->layout() );
|
||||||
|
if ( tl == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QSize visibleSize = viewport()->contentsRect().size();
|
||||||
|
|
||||||
|
const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
|
||||||
|
|
||||||
|
int w = qMax( visibleSize.width(), minW );
|
||||||
|
int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||||
|
|
||||||
|
const int vpWidth = viewportSize( w, h ).width();
|
||||||
|
if ( w > vpWidth )
|
||||||
|
{
|
||||||
|
w = qMax( vpWidth, minW );
|
||||||
|
h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||||
|
}
|
||||||
|
|
||||||
|
contentsWidget->resize( w, h );
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *contentsWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtLegend::QwtLegend( QWidget *parent ):
|
||||||
|
QwtAbstractLegend( parent )
|
||||||
|
{
|
||||||
|
setFrameStyle( NoFrame );
|
||||||
|
|
||||||
|
d_data = new QwtLegend::PrivateData;
|
||||||
|
|
||||||
|
d_data->view = new QwtLegend::PrivateData::LegendView( this );
|
||||||
|
d_data->view->setObjectName( "QwtLegendView" );
|
||||||
|
d_data->view->setFrameStyle( NoFrame );
|
||||||
|
|
||||||
|
QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
|
||||||
|
d_data->view->contentsWidget );
|
||||||
|
gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
|
||||||
|
|
||||||
|
d_data->view->contentsWidget->installEventFilter( this );
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout( this );
|
||||||
|
layout->setContentsMargins( 0, 0, 0, 0 );
|
||||||
|
layout->addWidget( d_data->view );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtLegend::~QwtLegend()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the maximum number of entries in a row
|
||||||
|
|
||||||
|
F.e when the maximum is set to 1 all items are aligned
|
||||||
|
vertically. 0 means unlimited
|
||||||
|
|
||||||
|
\param numColums Maximum number of entries in a row
|
||||||
|
|
||||||
|
\sa maxColumns(), QwtDynGridLayout::setMaxColumns()
|
||||||
|
*/
|
||||||
|
void QwtLegend::setMaxColumns( uint numColums )
|
||||||
|
{
|
||||||
|
QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||||
|
d_data->view->contentsWidget->layout() );
|
||||||
|
if ( tl )
|
||||||
|
tl->setMaxColumns( numColums );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Maximum number of entries in a row
|
||||||
|
\sa setMaxColumns(), QwtDynGridLayout::maxColumns()
|
||||||
|
*/
|
||||||
|
uint QwtLegend::maxColumns() const
|
||||||
|
{
|
||||||
|
uint maxCols = 0;
|
||||||
|
|
||||||
|
const QwtDynGridLayout *tl = qobject_cast<const QwtDynGridLayout *>(
|
||||||
|
d_data->view->contentsWidget->layout() );
|
||||||
|
if ( tl )
|
||||||
|
maxCols = tl->maxColumns();
|
||||||
|
|
||||||
|
return maxCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the default mode for legend labels
|
||||||
|
|
||||||
|
Legend labels will be constructed according to the
|
||||||
|
attributes in a QwtLegendData object. When it doesn't
|
||||||
|
contain a value for the QwtLegendData::ModeRole the
|
||||||
|
label will be initialized with the default mode of the legend.
|
||||||
|
|
||||||
|
\param mode Default item mode
|
||||||
|
|
||||||
|
\sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData()
|
||||||
|
\note Changing the mode doesn't have any effect on existing labels.
|
||||||
|
*/
|
||||||
|
void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode )
|
||||||
|
{
|
||||||
|
d_data->itemMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Default item mode
|
||||||
|
\sa setDefaultItemMode()
|
||||||
|
*/
|
||||||
|
QwtLegendData::Mode QwtLegend::defaultItemMode() const
|
||||||
|
{
|
||||||
|
return d_data->itemMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The contents widget is the only child of the viewport of
|
||||||
|
the internal QScrollArea and the parent widget of all legend items.
|
||||||
|
|
||||||
|
\return Container widget of the legend items
|
||||||
|
*/
|
||||||
|
QWidget *QwtLegend::contentsWidget()
|
||||||
|
{
|
||||||
|
return d_data->view->contentsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Horizontal scrollbar
|
||||||
|
\sa verticalScrollBar()
|
||||||
|
*/
|
||||||
|
QScrollBar *QwtLegend::horizontalScrollBar() const
|
||||||
|
{
|
||||||
|
return d_data->view->horizontalScrollBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Vertical scrollbar
|
||||||
|
\sa horizontalScrollBar()
|
||||||
|
*/
|
||||||
|
QScrollBar *QwtLegend::verticalScrollBar() const
|
||||||
|
{
|
||||||
|
return d_data->view->verticalScrollBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The contents widget is the only child of the viewport of
|
||||||
|
the internal QScrollArea and the parent widget of all legend items.
|
||||||
|
|
||||||
|
\return Container widget of the legend items
|
||||||
|
|
||||||
|
*/
|
||||||
|
const QWidget *QwtLegend::contentsWidget() const
|
||||||
|
{
|
||||||
|
return d_data->view->contentsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Update the entries for an item
|
||||||
|
|
||||||
|
\param itemInfo Info for an item
|
||||||
|
\param legendData List of legend entry attributes for the item
|
||||||
|
*/
|
||||||
|
void QwtLegend::updateLegend( const QVariant &itemInfo,
|
||||||
|
const QList<QwtLegendData> &legendData )
|
||||||
|
{
|
||||||
|
QList<QWidget *> widgetList = legendWidgets( itemInfo );
|
||||||
|
|
||||||
|
if ( widgetList.size() != legendData.size() )
|
||||||
|
{
|
||||||
|
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||||
|
|
||||||
|
while ( widgetList.size() > legendData.size() )
|
||||||
|
{
|
||||||
|
QWidget *w = widgetList.takeLast();
|
||||||
|
|
||||||
|
contentsLayout->removeWidget( w );
|
||||||
|
|
||||||
|
// updates might be triggered by signals from the legend widget
|
||||||
|
// itself. So we better don't delete it here.
|
||||||
|
|
||||||
|
w->hide();
|
||||||
|
w->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x040700
|
||||||
|
widgetList.reserve( legendData.size() );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for ( int i = widgetList.size(); i < legendData.size(); i++ )
|
||||||
|
{
|
||||||
|
QWidget *widget = createWidget( legendData[i] );
|
||||||
|
|
||||||
|
if ( contentsLayout )
|
||||||
|
contentsLayout->addWidget( widget );
|
||||||
|
|
||||||
|
if ( isVisible() )
|
||||||
|
{
|
||||||
|
// QLayout does a delayed show, with the effect, that
|
||||||
|
// the size hint will be wrong, when applications
|
||||||
|
// call replot() right after changing the list
|
||||||
|
// of plot items. So we better do the show now.
|
||||||
|
|
||||||
|
widget->setVisible( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetList += widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( widgetList.isEmpty() )
|
||||||
|
{
|
||||||
|
d_data->itemMap.remove( itemInfo );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d_data->itemMap.insert( itemInfo, widgetList );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTabOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < legendData.size(); i++ )
|
||||||
|
updateWidget( widgetList[i], legendData[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Create a widget to be inserted into the legend
|
||||||
|
|
||||||
|
The default implementation returns a QwtLegendLabel.
|
||||||
|
|
||||||
|
\param legendData Attributes of the legend entry
|
||||||
|
\return Widget representing data on the legend
|
||||||
|
|
||||||
|
\note updateWidget() will called soon after createWidget()
|
||||||
|
with the same attributes.
|
||||||
|
*/
|
||||||
|
QWidget *QwtLegend::createWidget( const QwtLegendData &legendData ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( legendData );
|
||||||
|
|
||||||
|
QwtLegendLabel *label = new QwtLegendLabel();
|
||||||
|
label->setItemMode( defaultItemMode() );
|
||||||
|
|
||||||
|
connect( label, SIGNAL(clicked()), SLOT(itemClicked()) );
|
||||||
|
connect( label, SIGNAL(checked(bool)), SLOT(itemChecked(bool)) );
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Update the widget
|
||||||
|
|
||||||
|
\param widget Usually a QwtLegendLabel
|
||||||
|
\param legendData Attributes to be displayed
|
||||||
|
|
||||||
|
\sa createWidget()
|
||||||
|
\note When widget is no QwtLegendLabel updateWidget() does nothing.
|
||||||
|
*/
|
||||||
|
void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &legendData )
|
||||||
|
{
|
||||||
|
QwtLegendLabel *label = qobject_cast<QwtLegendLabel *>( widget );
|
||||||
|
if ( label )
|
||||||
|
{
|
||||||
|
label->setData( legendData );
|
||||||
|
if ( !legendData.value( QwtLegendData::ModeRole ).isValid() )
|
||||||
|
{
|
||||||
|
// use the default mode, when there is no specific
|
||||||
|
// hint from the legend data
|
||||||
|
|
||||||
|
label->setItemMode( defaultItemMode() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtLegend::updateTabOrder()
|
||||||
|
{
|
||||||
|
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||||
|
if ( contentsLayout )
|
||||||
|
{
|
||||||
|
// set tab focus chain
|
||||||
|
|
||||||
|
QWidget *w = NULL;
|
||||||
|
|
||||||
|
for ( int i = 0; i < contentsLayout->count(); i++ )
|
||||||
|
{
|
||||||
|
QLayoutItem *item = contentsLayout->itemAt( i );
|
||||||
|
if ( w && item->widget() )
|
||||||
|
QWidget::setTabOrder( w, item->widget() );
|
||||||
|
|
||||||
|
w = item->widget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return a size hint.
|
||||||
|
QSize QwtLegend::sizeHint() const
|
||||||
|
{
|
||||||
|
QSize hint = d_data->view->contentsWidget->sizeHint();
|
||||||
|
hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
|
||||||
|
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return The preferred height, for a width.
|
||||||
|
\param width Width
|
||||||
|
*/
|
||||||
|
int QwtLegend::heightForWidth( int width ) const
|
||||||
|
{
|
||||||
|
width -= 2 * frameWidth();
|
||||||
|
|
||||||
|
int h = d_data->view->contentsWidget->heightForWidth( width );
|
||||||
|
if ( h >= 0 )
|
||||||
|
h += 2 * frameWidth();
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
|
||||||
|
for the contentsWidget().
|
||||||
|
|
||||||
|
\param object Object to be filtered
|
||||||
|
\param event Event
|
||||||
|
|
||||||
|
\return Forwarded to QwtAbstractLegend::eventFilter()
|
||||||
|
*/
|
||||||
|
bool QwtLegend::eventFilter( QObject *object, QEvent *event )
|
||||||
|
{
|
||||||
|
if ( object == d_data->view->contentsWidget )
|
||||||
|
{
|
||||||
|
switch ( event->type() )
|
||||||
|
{
|
||||||
|
case QEvent::ChildRemoved:
|
||||||
|
{
|
||||||
|
const QChildEvent *ce =
|
||||||
|
static_cast<const QChildEvent *>(event);
|
||||||
|
|
||||||
|
if ( ce->child()->isWidgetType() )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We are called from the ~QObject and ce->child() is
|
||||||
|
no widget anymore. But all we need is the address
|
||||||
|
to remove it from the map.
|
||||||
|
*/
|
||||||
|
QWidget *w = reinterpret_cast< QWidget * >( ce->child() );
|
||||||
|
d_data->itemMap.removeWidget( w );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::LayoutRequest:
|
||||||
|
{
|
||||||
|
d_data->view->layoutContents();
|
||||||
|
|
||||||
|
if ( parentWidget() && parentWidget()->layout() == NULL )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We want the parent widget ( usually QwtPlot ) to recalculate
|
||||||
|
its layout, when the contentsWidget has changed. But
|
||||||
|
because of the scroll view we have to forward the LayoutRequest
|
||||||
|
event manually.
|
||||||
|
|
||||||
|
We don't use updateGeometry() because it doesn't post LayoutRequest
|
||||||
|
events when the legend is hidden. But we want the
|
||||||
|
parent widget notified, so it can show/hide the legend
|
||||||
|
depending on its items.
|
||||||
|
*/
|
||||||
|
QApplication::postEvent( parentWidget(),
|
||||||
|
new QEvent( QEvent::LayoutRequest ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QwtAbstractLegend::eventFilter( object, event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called internally when the legend has been clicked on.
|
||||||
|
Emits a clicked() signal.
|
||||||
|
*/
|
||||||
|
void QwtLegend::itemClicked()
|
||||||
|
{
|
||||||
|
QWidget *w = qobject_cast<QWidget *>( sender() );
|
||||||
|
if ( w )
|
||||||
|
{
|
||||||
|
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
|
||||||
|
if ( itemInfo.isValid() )
|
||||||
|
{
|
||||||
|
const QList<QWidget *> widgetList =
|
||||||
|
d_data->itemMap.legendWidgets( itemInfo );
|
||||||
|
|
||||||
|
const int index = widgetList.indexOf( w );
|
||||||
|
if ( index >= 0 )
|
||||||
|
Q_EMIT clicked( itemInfo, index );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called internally when the legend has been checked
|
||||||
|
Emits a checked() signal.
|
||||||
|
*/
|
||||||
|
void QwtLegend::itemChecked( bool on )
|
||||||
|
{
|
||||||
|
QWidget *w = qobject_cast<QWidget *>( sender() );
|
||||||
|
if ( w )
|
||||||
|
{
|
||||||
|
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
|
||||||
|
if ( itemInfo.isValid() )
|
||||||
|
{
|
||||||
|
const QList<QWidget *> widgetList =
|
||||||
|
d_data->itemMap.legendWidgets( itemInfo );
|
||||||
|
|
||||||
|
const int index = widgetList.indexOf( w );
|
||||||
|
if ( index >= 0 )
|
||||||
|
Q_EMIT checked( itemInfo, on, index );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Render the legend into a given rectangle.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param rect Bounding rectangle
|
||||||
|
\param fillBackground When true, fill rect with the widget background
|
||||||
|
|
||||||
|
\sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself
|
||||||
|
*/
|
||||||
|
void QwtLegend::renderLegend( QPainter *painter,
|
||||||
|
const QRectF &rect, bool fillBackground ) const
|
||||||
|
{
|
||||||
|
if ( d_data->itemMap.isEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( fillBackground )
|
||||||
|
{
|
||||||
|
if ( autoFillBackground() ||
|
||||||
|
testAttribute( Qt::WA_StyledBackground ) )
|
||||||
|
{
|
||||||
|
QwtPainter::drawBackgound( painter, rect, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QwtDynGridLayout *legendLayout =
|
||||||
|
qobject_cast<QwtDynGridLayout *>( contentsWidget()->layout() );
|
||||||
|
if ( legendLayout == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int left, right, top, bottom;
|
||||||
|
getContentsMargins( &left, &top, &right, &bottom );
|
||||||
|
|
||||||
|
QRect layoutRect;
|
||||||
|
layoutRect.setLeft( qCeil( rect.left() ) + left );
|
||||||
|
layoutRect.setTop( qCeil( rect.top() ) + top );
|
||||||
|
layoutRect.setRight( qFloor( rect.right() ) - right );
|
||||||
|
layoutRect.setBottom( qFloor( rect.bottom() ) - bottom );
|
||||||
|
|
||||||
|
uint numCols = legendLayout->columnsForWidth( layoutRect.width() );
|
||||||
|
const QList<QRect> itemRects =
|
||||||
|
legendLayout->layoutItems( layoutRect, numCols );
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < legendLayout->count(); i++ )
|
||||||
|
{
|
||||||
|
QLayoutItem *item = legendLayout->itemAt( i );
|
||||||
|
QWidget *w = item->widget();
|
||||||
|
if ( w )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
painter->setClipRect( itemRects[index], Qt::IntersectClip );
|
||||||
|
renderItem( painter, w, itemRects[index], fillBackground );
|
||||||
|
|
||||||
|
index++;
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Render a legend entry into a given rectangle.
|
||||||
|
|
||||||
|
\param painter Painter
|
||||||
|
\param widget Widget representing a legend entry
|
||||||
|
\param rect Bounding rectangle
|
||||||
|
\param fillBackground When true, fill rect with the widget background
|
||||||
|
|
||||||
|
\note When widget is not derived from QwtLegendLabel renderItem
|
||||||
|
does nothing beside the background
|
||||||
|
*/
|
||||||
|
void QwtLegend::renderItem( QPainter *painter,
|
||||||
|
const QWidget *widget, const QRectF &rect, bool fillBackground ) const
|
||||||
|
{
|
||||||
|
if ( fillBackground )
|
||||||
|
{
|
||||||
|
if ( widget->autoFillBackground() ||
|
||||||
|
widget->testAttribute( Qt::WA_StyledBackground ) )
|
||||||
|
{
|
||||||
|
QwtPainter::drawBackgound( painter, rect, widget );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QwtLegendLabel *label = qobject_cast<const QwtLegendLabel *>( widget );
|
||||||
|
if ( label )
|
||||||
|
{
|
||||||
|
// icon
|
||||||
|
|
||||||
|
const QwtGraphic &icon = label->data().icon();
|
||||||
|
const QSizeF sz = icon.defaultSize();
|
||||||
|
|
||||||
|
const QRectF iconRect( rect.x() + label->margin(),
|
||||||
|
rect.center().y() - 0.5 * sz.height(),
|
||||||
|
sz.width(), sz.height() );
|
||||||
|
|
||||||
|
icon.render( painter, iconRect, Qt::KeepAspectRatio );
|
||||||
|
|
||||||
|
// title
|
||||||
|
|
||||||
|
QRectF titleRect = rect;
|
||||||
|
titleRect.setX( iconRect.right() + 2 * label->spacing() );
|
||||||
|
|
||||||
|
QFont labelFont = label->font();
|
||||||
|
labelFont.resolve( QFont::AllPropertiesResolved );
|
||||||
|
|
||||||
|
painter->setFont( labelFont );
|
||||||
|
painter->setPen( label->palette().color( QPalette::Text ) );
|
||||||
|
|
||||||
|
const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return List of widgets associated to a item
|
||||||
|
\param itemInfo Info about an item
|
||||||
|
\sa legendWidget(), itemInfo(), QwtPlot::itemToInfo()
|
||||||
|
*/
|
||||||
|
QList<QWidget *> QwtLegend::legendWidgets( const QVariant &itemInfo ) const
|
||||||
|
{
|
||||||
|
return d_data->itemMap.legendWidgets( itemInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return First widget in the list of widgets associated to an item
|
||||||
|
\param itemInfo Info about an item
|
||||||
|
\sa itemInfo(), QwtPlot::itemToInfo()
|
||||||
|
\note Almost all types of items have only one widget
|
||||||
|
*/
|
||||||
|
QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const
|
||||||
|
{
|
||||||
|
const QList<QWidget *> list = d_data->itemMap.legendWidgets( itemInfo );
|
||||||
|
if ( list.isEmpty() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return list[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Find the item that is associated to a widget
|
||||||
|
|
||||||
|
\param widget Widget on the legend
|
||||||
|
\return Associated item info
|
||||||
|
\sa legendWidget()
|
||||||
|
*/
|
||||||
|
QVariant QwtLegend::itemInfo( const QWidget *widget ) const
|
||||||
|
{
|
||||||
|
return d_data->itemMap.itemInfo( widget );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return True, when no item is inserted
|
||||||
|
bool QwtLegend::isEmpty() const
|
||||||
|
{
|
||||||
|
return d_data->itemMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return the extent, that is needed for the scrollbars
|
||||||
|
|
||||||
|
\param orientation Orientation
|
||||||
|
\return The width of the vertical scrollbar for Qt::Horizontal and v.v.
|
||||||
|
*/
|
||||||
|
int QwtLegend::scrollExtent( Qt::Orientation orientation ) const
|
||||||
|
{
|
||||||
|
int extent = 0;
|
||||||
|
|
||||||
|
if ( orientation == Qt::Horizontal )
|
||||||
|
extent = verticalScrollBar()->sizeHint().width();
|
||||||
|
else
|
||||||
|
extent = horizontalScrollBar()->sizeHint().height();
|
||||||
|
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_LEGEND_H
|
||||||
|
#define QWT_LEGEND_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_abstract_legend.h"
|
||||||
|
#include <qvariant.h>
|
||||||
|
|
||||||
|
class QScrollBar;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The legend widget
|
||||||
|
|
||||||
|
The QwtLegend widget is a tabular arrangement of legend items. Legend
|
||||||
|
items might be any type of widget, but in general they will be
|
||||||
|
a QwtLegendLabel.
|
||||||
|
|
||||||
|
\sa QwtLegendLabel, QwtPlotItem, QwtPlot
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtLegend : public QwtAbstractLegend
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QwtLegend( QWidget *parent = NULL );
|
||||||
|
virtual ~QwtLegend();
|
||||||
|
|
||||||
|
void setMaxColumns( uint numColums );
|
||||||
|
uint maxColumns() const;
|
||||||
|
|
||||||
|
void setDefaultItemMode( QwtLegendData::Mode );
|
||||||
|
QwtLegendData::Mode defaultItemMode() const;
|
||||||
|
|
||||||
|
QWidget *contentsWidget();
|
||||||
|
const QWidget *contentsWidget() const;
|
||||||
|
|
||||||
|
QWidget *legendWidget( const QVariant & ) const;
|
||||||
|
QList<QWidget *> legendWidgets( const QVariant & ) const;
|
||||||
|
|
||||||
|
QVariant itemInfo( const QWidget * ) const;
|
||||||
|
|
||||||
|
virtual bool eventFilter( QObject *, QEvent * );
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
virtual int heightForWidth( int width ) const;
|
||||||
|
|
||||||
|
QScrollBar *horizontalScrollBar() const;
|
||||||
|
QScrollBar *verticalScrollBar() const;
|
||||||
|
|
||||||
|
virtual void renderLegend( QPainter *,
|
||||||
|
const QRectF &, bool fillBackground ) const;
|
||||||
|
|
||||||
|
virtual void renderItem( QPainter *,
|
||||||
|
const QWidget *, const QRectF &, bool fillBackground ) const;
|
||||||
|
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
virtual int scrollExtent( Qt::Orientation ) const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/*!
|
||||||
|
A signal which is emitted when the user has clicked on
|
||||||
|
a legend label, which is in QwtLegendData::Clickable mode.
|
||||||
|
|
||||||
|
\param itemInfo Info for the item item of the
|
||||||
|
selected legend item
|
||||||
|
\param index Index of the legend label in the list of widgets
|
||||||
|
that are associated with the plot item
|
||||||
|
|
||||||
|
\note clicks are disabled as default
|
||||||
|
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
|
||||||
|
*/
|
||||||
|
void clicked( const QVariant &itemInfo, int index );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A signal which is emitted when the user has clicked on
|
||||||
|
a legend label, which is in QwtLegendData::Checkable mode
|
||||||
|
|
||||||
|
\param itemInfo Info for the item of the
|
||||||
|
selected legend label
|
||||||
|
\param index Index of the legend label in the list of widgets
|
||||||
|
that are associated with the plot item
|
||||||
|
\param on True when the legend label is checked
|
||||||
|
|
||||||
|
\note clicks are disabled as default
|
||||||
|
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
|
||||||
|
*/
|
||||||
|
void checked( const QVariant &itemInfo, bool on, int index );
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
virtual void updateLegend( const QVariant &,
|
||||||
|
const QList<QwtLegendData> & );
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void itemClicked();
|
||||||
|
void itemChecked( bool );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QWidget *createWidget( const QwtLegendData & ) const;
|
||||||
|
virtual void updateWidget( QWidget *widget, const QwtLegendData & );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateTabOrder();
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
/* -*- 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 "qwt_legend_data.h"
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
QwtLegendData::QwtLegendData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtLegendData::~QwtLegendData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the legend attributes
|
||||||
|
|
||||||
|
QwtLegendData actually is a QMap<int, QVariant> with some
|
||||||
|
convenience interfaces
|
||||||
|
|
||||||
|
\param map Values
|
||||||
|
\sa values()
|
||||||
|
*/
|
||||||
|
void QwtLegendData::setValues( const QMap<int, QVariant> &map )
|
||||||
|
{
|
||||||
|
d_map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Legend attributes
|
||||||
|
\sa setValues()
|
||||||
|
*/
|
||||||
|
const QMap<int, QVariant> &QwtLegendData::values() const
|
||||||
|
{
|
||||||
|
return d_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param role Attribute role
|
||||||
|
\return True, when the internal map has an entry for role
|
||||||
|
*/
|
||||||
|
bool QwtLegendData::hasRole( int role ) const
|
||||||
|
{
|
||||||
|
return d_map.contains( role );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set an attribute value
|
||||||
|
|
||||||
|
\param role Attribute role
|
||||||
|
\param data Attribute value
|
||||||
|
|
||||||
|
\sa value()
|
||||||
|
*/
|
||||||
|
void QwtLegendData::setValue( int role, const QVariant &data )
|
||||||
|
{
|
||||||
|
d_map[role] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param role Attribute role
|
||||||
|
\return Attribute value for a specific role
|
||||||
|
*/
|
||||||
|
QVariant QwtLegendData::value( int role ) const
|
||||||
|
{
|
||||||
|
if ( !d_map.contains( role ) )
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
return d_map[role];
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return True, when the internal map is empty
|
||||||
|
bool QwtLegendData::isValid() const
|
||||||
|
{
|
||||||
|
return !d_map.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Value of the TitleRole attribute
|
||||||
|
QwtText QwtLegendData::title() const
|
||||||
|
{
|
||||||
|
QwtText text;
|
||||||
|
|
||||||
|
const QVariant titleValue = value( QwtLegendData::TitleRole );
|
||||||
|
if ( titleValue.canConvert<QwtText>() )
|
||||||
|
{
|
||||||
|
text = qvariant_cast<QwtText>( titleValue );
|
||||||
|
}
|
||||||
|
else if ( titleValue.canConvert<QString>() )
|
||||||
|
{
|
||||||
|
text.setText( qvariant_cast<QString>( titleValue ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Value of the IconRole attribute
|
||||||
|
QwtGraphic QwtLegendData::icon() const
|
||||||
|
{
|
||||||
|
const QVariant iconValue = value( QwtLegendData::IconRole );
|
||||||
|
|
||||||
|
QwtGraphic graphic;
|
||||||
|
if ( iconValue.canConvert<QwtGraphic>() )
|
||||||
|
{
|
||||||
|
graphic = qvariant_cast<QwtGraphic>( iconValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
return graphic;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Value of the ModeRole attribute
|
||||||
|
QwtLegendData::Mode QwtLegendData::mode() const
|
||||||
|
{
|
||||||
|
const QVariant modeValue = value( QwtLegendData::ModeRole );
|
||||||
|
if ( modeValue.canConvert<int>() )
|
||||||
|
{
|
||||||
|
const int mode = qvariant_cast<int>( modeValue );
|
||||||
|
return static_cast<QwtLegendData::Mode>( mode );
|
||||||
|
}
|
||||||
|
|
||||||
|
return QwtLegendData::ReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_LEGEND_DATA_H
|
||||||
|
#define QWT_LEGEND_DATA_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
|
#include "qwt_graphic.h"
|
||||||
|
#include <qvariant.h>
|
||||||
|
#include <qpixmap.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Attributes of an entry on a legend
|
||||||
|
|
||||||
|
QwtLegendData is an abstract container ( like QAbstractModel )
|
||||||
|
to exchange attributes, that are only known between to
|
||||||
|
the plot item and the legend.
|
||||||
|
|
||||||
|
By overloading QwtPlotItem::legendData() any other set of attributes
|
||||||
|
could be used, that can be handled by a modified ( or completely
|
||||||
|
different ) implementation of a legend.
|
||||||
|
|
||||||
|
\sa QwtLegend, QwtPlotLegendItem
|
||||||
|
\note The stockchart example implements a legend as a tree
|
||||||
|
with checkable items
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtLegendData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Mode defining how a legend entry interacts
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
//! The legend item is not interactive, like a label
|
||||||
|
ReadOnly,
|
||||||
|
|
||||||
|
//! The legend item is clickable, like a push button
|
||||||
|
Clickable,
|
||||||
|
|
||||||
|
//! The legend item is checkable, like a checkable button
|
||||||
|
Checkable
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Identifier how to interprete a QVariant
|
||||||
|
enum Role
|
||||||
|
{
|
||||||
|
// The value is a Mode
|
||||||
|
ModeRole,
|
||||||
|
|
||||||
|
// The value is a title
|
||||||
|
TitleRole,
|
||||||
|
|
||||||
|
// The value is an icon
|
||||||
|
IconRole,
|
||||||
|
|
||||||
|
// Values < UserRole are reserved for internal use
|
||||||
|
UserRole = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtLegendData();
|
||||||
|
~QwtLegendData();
|
||||||
|
|
||||||
|
void setValues( const QMap<int, QVariant> & );
|
||||||
|
const QMap<int, QVariant> &values() const;
|
||||||
|
|
||||||
|
void setValue( int role, const QVariant & );
|
||||||
|
QVariant value( int role ) const;
|
||||||
|
|
||||||
|
bool hasRole( int role ) const;
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
QwtGraphic icon() const;
|
||||||
|
QwtText title() const;
|
||||||
|
Mode mode() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<int, QVariant> d_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,421 @@
|
|||||||
|
/* -*- 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 "qwt_legend_label.h"
|
||||||
|
#include "qwt_legend_data.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include "qwt_symbol.h"
|
||||||
|
#include "qwt_graphic.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qdrawutil.h>
|
||||||
|
#include <qstyle.h>
|
||||||
|
#include <qpen.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qstyleoption.h>
|
||||||
|
#include <qapplication.h>
|
||||||
|
|
||||||
|
static const int ButtonFrame = 2;
|
||||||
|
static const int Margin = 2;
|
||||||
|
|
||||||
|
static QSize buttonShift( const QwtLegendLabel *w )
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
return QSize( ph, pv );
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtLegendLabel::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
itemMode( QwtLegendData::ReadOnly ),
|
||||||
|
isDown( false ),
|
||||||
|
spacing( Margin )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtLegendData::Mode itemMode;
|
||||||
|
QwtLegendData legendData;
|
||||||
|
bool isDown;
|
||||||
|
|
||||||
|
QPixmap icon;
|
||||||
|
|
||||||
|
int spacing;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the attributes of the legend label
|
||||||
|
|
||||||
|
\param legendData Attributes of the label
|
||||||
|
\sa data()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setData( const QwtLegendData &legendData )
|
||||||
|
{
|
||||||
|
d_data->legendData = legendData;
|
||||||
|
|
||||||
|
const bool doUpdate = updatesEnabled();
|
||||||
|
setUpdatesEnabled( false );
|
||||||
|
|
||||||
|
setText( legendData.title() );
|
||||||
|
setIcon( legendData.icon().toPixmap() );
|
||||||
|
|
||||||
|
if ( legendData.hasRole( QwtLegendData::ModeRole ) )
|
||||||
|
setItemMode( legendData.mode() );
|
||||||
|
|
||||||
|
if ( doUpdate )
|
||||||
|
{
|
||||||
|
setUpdatesEnabled( true );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Attributes of the label
|
||||||
|
\sa setData(), QwtPlotItem::legendData()
|
||||||
|
*/
|
||||||
|
const QwtLegendData &QwtLegendLabel::data() const
|
||||||
|
{
|
||||||
|
return d_data->legendData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\param parent Parent widget
|
||||||
|
*/
|
||||||
|
QwtLegendLabel::QwtLegendLabel( QWidget *parent ):
|
||||||
|
QwtTextLabel( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData;
|
||||||
|
setMargin( Margin );
|
||||||
|
setIndent( Margin );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtLegendLabel::~QwtLegendLabel()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
d_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the text to the legend item
|
||||||
|
|
||||||
|
\param text Text label
|
||||||
|
\sa QwtTextLabel::text()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setText( const QwtText &text )
|
||||||
|
{
|
||||||
|
const int flags = Qt::AlignLeft | Qt::AlignVCenter
|
||||||
|
| Qt::TextExpandTabs | Qt::TextWordWrap;
|
||||||
|
|
||||||
|
QwtText txt = text;
|
||||||
|
txt.setRenderFlags( flags );
|
||||||
|
|
||||||
|
QwtTextLabel::setText( txt );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the item mode
|
||||||
|
The default is QwtLegendData::ReadOnly
|
||||||
|
|
||||||
|
\param mode Item mode
|
||||||
|
\sa itemMode()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setItemMode( QwtLegendData::Mode mode )
|
||||||
|
{
|
||||||
|
if ( mode != d_data->itemMode )
|
||||||
|
{
|
||||||
|
d_data->itemMode = mode;
|
||||||
|
d_data->isDown = false;
|
||||||
|
|
||||||
|
setFocusPolicy( ( mode != QwtLegendData::ReadOnly )
|
||||||
|
? Qt::TabFocus : Qt::NoFocus );
|
||||||
|
setMargin( ButtonFrame + Margin );
|
||||||
|
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Item mode
|
||||||
|
\sa setItemMode()
|
||||||
|
*/
|
||||||
|
QwtLegendData::Mode QwtLegendLabel::itemMode() const
|
||||||
|
{
|
||||||
|
return d_data->itemMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the icon
|
||||||
|
|
||||||
|
\param icon Pixmap representing a plot item
|
||||||
|
|
||||||
|
\sa icon(), QwtPlotItem::legendIcon()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setIcon( const QPixmap &icon )
|
||||||
|
{
|
||||||
|
d_data->icon = icon;
|
||||||
|
|
||||||
|
int indent = margin() + d_data->spacing;
|
||||||
|
if ( icon.width() > 0 )
|
||||||
|
indent += icon.width() + d_data->spacing;
|
||||||
|
|
||||||
|
setIndent( indent );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Pixmap representing a plot item
|
||||||
|
\sa setIcon()
|
||||||
|
*/
|
||||||
|
QPixmap QwtLegendLabel::icon() const
|
||||||
|
{
|
||||||
|
return d_data->icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the spacing between icon and text
|
||||||
|
|
||||||
|
\param spacing Spacing
|
||||||
|
\sa spacing(), QwtTextLabel::margin()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setSpacing( int spacing )
|
||||||
|
{
|
||||||
|
spacing = qMax( spacing, 0 );
|
||||||
|
if ( spacing != d_data->spacing )
|
||||||
|
{
|
||||||
|
d_data->spacing = spacing;
|
||||||
|
|
||||||
|
int indent = margin() + d_data->spacing;
|
||||||
|
if ( d_data->icon.width() > 0 )
|
||||||
|
indent += d_data->icon.width() + d_data->spacing;
|
||||||
|
|
||||||
|
setIndent( indent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Spacing between icon and text
|
||||||
|
\sa setSpacing(), QwtTextLabel::margin()
|
||||||
|
*/
|
||||||
|
int QwtLegendLabel::spacing() const
|
||||||
|
{
|
||||||
|
return d_data->spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Check/Uncheck a the item
|
||||||
|
|
||||||
|
\param on check/uncheck
|
||||||
|
\sa setItemMode()
|
||||||
|
*/
|
||||||
|
void QwtLegendLabel::setChecked( bool on )
|
||||||
|
{
|
||||||
|
if ( d_data->itemMode == QwtLegendData::Checkable )
|
||||||
|
{
|
||||||
|
const bool isBlocked = signalsBlocked();
|
||||||
|
blockSignals( true );
|
||||||
|
|
||||||
|
setDown( on );
|
||||||
|
|
||||||
|
blockSignals( isBlocked );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return true, if the item is checked
|
||||||
|
bool QwtLegendLabel::isChecked() const
|
||||||
|
{
|
||||||
|
return d_data->itemMode == QwtLegendData::Checkable && isDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Set the item being down
|
||||||
|
void QwtLegendLabel::setDown( bool down )
|
||||||
|
{
|
||||||
|
if ( down == d_data->isDown )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data->isDown = down;
|
||||||
|
update();
|
||||||
|
|
||||||
|
if ( d_data->itemMode == QwtLegendData::Clickable )
|
||||||
|
{
|
||||||
|
if ( d_data->isDown )
|
||||||
|
Q_EMIT pressed();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT released();
|
||||||
|
Q_EMIT clicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->itemMode == QwtLegendData::Checkable )
|
||||||
|
Q_EMIT checked( d_data->isDown );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return true, if the item is down
|
||||||
|
bool QwtLegendLabel::isDown() const
|
||||||
|
{
|
||||||
|
return d_data->isDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return a size hint
|
||||||
|
QSize QwtLegendLabel::sizeHint() const
|
||||||
|
{
|
||||||
|
QSize sz = QwtTextLabel::sizeHint();
|
||||||
|
sz.setHeight( qMax( sz.height(), d_data->icon.height() + 4 ) );
|
||||||
|
|
||||||
|
if ( d_data->itemMode != QwtLegendData::ReadOnly )
|
||||||
|
{
|
||||||
|
sz += buttonShift( this );
|
||||||
|
sz = sz.expandedTo( QApplication::globalStrut() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Paint event
|
||||||
|
void QwtLegendLabel::paintEvent( QPaintEvent *e )
|
||||||
|
{
|
||||||
|
const QRect cr = contentsRect();
|
||||||
|
|
||||||
|
QPainter painter( this );
|
||||||
|
painter.setClipRegion( e->region() );
|
||||||
|
|
||||||
|
if ( d_data->isDown )
|
||||||
|
{
|
||||||
|
qDrawWinButton( &painter, 0, 0, width(), height(),
|
||||||
|
palette(), true );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.save();
|
||||||
|
|
||||||
|
if ( d_data->isDown )
|
||||||
|
{
|
||||||
|
const QSize shiftSize = buttonShift( this );
|
||||||
|
painter.translate( shiftSize.width(), shiftSize.height() );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setClipRect( cr );
|
||||||
|
|
||||||
|
drawContents( &painter );
|
||||||
|
|
||||||
|
if ( !d_data->icon.isNull() )
|
||||||
|
{
|
||||||
|
QRect iconRect = cr;
|
||||||
|
iconRect.setX( iconRect.x() + margin() );
|
||||||
|
if ( d_data->itemMode != QwtLegendData::ReadOnly )
|
||||||
|
iconRect.setX( iconRect.x() + ButtonFrame );
|
||||||
|
|
||||||
|
iconRect.setSize( d_data->icon.size() );
|
||||||
|
iconRect.moveCenter( QPoint( iconRect.center().x(), cr.center().y() ) );
|
||||||
|
|
||||||
|
painter.drawPixmap( iconRect, d_data->icon );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Handle mouse press events
|
||||||
|
void QwtLegendLabel::mousePressEvent( QMouseEvent *e )
|
||||||
|
{
|
||||||
|
if ( e->button() == Qt::LeftButton )
|
||||||
|
{
|
||||||
|
switch ( d_data->itemMode )
|
||||||
|
{
|
||||||
|
case QwtLegendData::Clickable:
|
||||||
|
{
|
||||||
|
setDown( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case QwtLegendData::Checkable:
|
||||||
|
{
|
||||||
|
setDown( !isDown() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QwtTextLabel::mousePressEvent( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Handle mouse release events
|
||||||
|
void QwtLegendLabel::mouseReleaseEvent( QMouseEvent *e )
|
||||||
|
{
|
||||||
|
if ( e->button() == Qt::LeftButton )
|
||||||
|
{
|
||||||
|
switch ( d_data->itemMode )
|
||||||
|
{
|
||||||
|
case QwtLegendData::Clickable:
|
||||||
|
{
|
||||||
|
setDown( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case QwtLegendData::Checkable:
|
||||||
|
{
|
||||||
|
return; // do nothing, but accept
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QwtTextLabel::mouseReleaseEvent( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Handle key press events
|
||||||
|
void QwtLegendLabel::keyPressEvent( QKeyEvent *e )
|
||||||
|
{
|
||||||
|
if ( e->key() == Qt::Key_Space )
|
||||||
|
{
|
||||||
|
switch ( d_data->itemMode )
|
||||||
|
{
|
||||||
|
case QwtLegendData::Clickable:
|
||||||
|
{
|
||||||
|
if ( !e->isAutoRepeat() )
|
||||||
|
setDown( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case QwtLegendData::Checkable:
|
||||||
|
{
|
||||||
|
if ( !e->isAutoRepeat() )
|
||||||
|
setDown( !isDown() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtTextLabel::keyPressEvent( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Handle key release events
|
||||||
|
void QwtLegendLabel::keyReleaseEvent( QKeyEvent *e )
|
||||||
|
{
|
||||||
|
if ( e->key() == Qt::Key_Space )
|
||||||
|
{
|
||||||
|
switch ( d_data->itemMode )
|
||||||
|
{
|
||||||
|
case QwtLegendData::Clickable:
|
||||||
|
{
|
||||||
|
if ( !e->isAutoRepeat() )
|
||||||
|
setDown( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case QwtLegendData::Checkable:
|
||||||
|
{
|
||||||
|
return; // do nothing, but accept
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtTextLabel::keyReleaseEvent( e );
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_LEGEND_LABEL_H
|
||||||
|
#define QWT_LEGEND_LABEL_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_legend_data.h"
|
||||||
|
#include "qwt_text.h"
|
||||||
|
#include "qwt_text_label.h"
|
||||||
|
#include <qpixmap.h>
|
||||||
|
|
||||||
|
class QwtLegendData;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A widget representing something on a QwtLegend.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtLegendLabel: public QwtTextLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit QwtLegendLabel( QWidget *parent = 0 );
|
||||||
|
virtual ~QwtLegendLabel();
|
||||||
|
|
||||||
|
void setData( const QwtLegendData & );
|
||||||
|
const QwtLegendData &data() const;
|
||||||
|
|
||||||
|
void setItemMode( QwtLegendData::Mode );
|
||||||
|
QwtLegendData::Mode itemMode() const;
|
||||||
|
|
||||||
|
void setSpacing( int spacing );
|
||||||
|
int spacing() const;
|
||||||
|
|
||||||
|
virtual void setText( const QwtText & );
|
||||||
|
|
||||||
|
void setIcon( const QPixmap & );
|
||||||
|
QPixmap icon() const;
|
||||||
|
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
|
||||||
|
bool isChecked() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setChecked( bool on );
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
//! Signal, when the legend item has been clicked
|
||||||
|
void clicked();
|
||||||
|
|
||||||
|
//! Signal, when the legend item has been pressed
|
||||||
|
void pressed();
|
||||||
|
|
||||||
|
//! Signal, when the legend item has been released
|
||||||
|
void released();
|
||||||
|
|
||||||
|
//! Signal, when the legend item has been toggled
|
||||||
|
void checked( bool );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setDown( bool );
|
||||||
|
bool isDown() const;
|
||||||
|
|
||||||
|
virtual void paintEvent( QPaintEvent * );
|
||||||
|
virtual void mousePressEvent( QMouseEvent * );
|
||||||
|
virtual void mouseReleaseEvent( QMouseEvent * );
|
||||||
|
virtual void keyPressEvent( QKeyEvent * );
|
||||||
|
virtual void keyReleaseEvent( QKeyEvent * );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,492 @@
|
|||||||
|
/* -*- 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 "qwt_magnifier.h"
|
||||||
|
#include "qwt_math.h"
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qwidget.h>
|
||||||
|
|
||||||
|
class QwtMagnifier::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
isEnabled( false ),
|
||||||
|
wheelFactor( 0.9 ),
|
||||||
|
wheelModifiers( Qt::NoModifier ),
|
||||||
|
mouseFactor( 0.95 ),
|
||||||
|
mouseButton( Qt::RightButton ),
|
||||||
|
mouseButtonModifiers( Qt::NoModifier ),
|
||||||
|
keyFactor( 0.9 ),
|
||||||
|
zoomInKey( Qt::Key_Plus ),
|
||||||
|
zoomInKeyModifiers( Qt::NoModifier ),
|
||||||
|
zoomOutKey( Qt::Key_Minus ),
|
||||||
|
zoomOutKeyModifiers( Qt::NoModifier ),
|
||||||
|
mousePressed( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled;
|
||||||
|
|
||||||
|
double wheelFactor;
|
||||||
|
Qt::KeyboardModifiers wheelModifiers;
|
||||||
|
|
||||||
|
double mouseFactor;
|
||||||
|
|
||||||
|
Qt::MouseButton mouseButton;
|
||||||
|
Qt::KeyboardModifiers mouseButtonModifiers;
|
||||||
|
|
||||||
|
double keyFactor;
|
||||||
|
|
||||||
|
int zoomInKey;
|
||||||
|
Qt::KeyboardModifiers zoomInKeyModifiers;
|
||||||
|
|
||||||
|
int zoomOutKey;
|
||||||
|
Qt::KeyboardModifiers zoomOutKeyModifiers;
|
||||||
|
|
||||||
|
bool mousePressed;
|
||||||
|
bool hasMouseTracking;
|
||||||
|
QPoint mousePos;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor
|
||||||
|
\param parent Widget to be magnified
|
||||||
|
*/
|
||||||
|
QwtMagnifier::QwtMagnifier( QWidget *parent ):
|
||||||
|
QObject( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
setEnabled( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtMagnifier::~QwtMagnifier()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief En/disable the magnifier
|
||||||
|
|
||||||
|
When enabled is true an event filter is installed for
|
||||||
|
the observed widget, otherwise the event filter is removed.
|
||||||
|
|
||||||
|
\param on true or false
|
||||||
|
\sa isEnabled(), eventFilter()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setEnabled( bool on )
|
||||||
|
{
|
||||||
|
if ( d_data->isEnabled != on )
|
||||||
|
{
|
||||||
|
d_data->isEnabled = on;
|
||||||
|
|
||||||
|
QObject *o = parent();
|
||||||
|
if ( o )
|
||||||
|
{
|
||||||
|
if ( d_data->isEnabled )
|
||||||
|
o->installEventFilter( this );
|
||||||
|
else
|
||||||
|
o->removeEventFilter( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return true when enabled, false otherwise
|
||||||
|
\sa setEnabled(), eventFilter()
|
||||||
|
*/
|
||||||
|
bool QwtMagnifier::isEnabled() const
|
||||||
|
{
|
||||||
|
return d_data->isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the wheel factor
|
||||||
|
|
||||||
|
The wheel factor defines the ratio between the current range
|
||||||
|
on the parent widget and the zoomed range for each step of the wheel.
|
||||||
|
|
||||||
|
Use values > 1 for magnification (i.e. 2.0) and values < 1 for
|
||||||
|
scaling down (i.e. 1/2.0 = 0.5). You can use this feature for
|
||||||
|
inverting the direction of the wheel.
|
||||||
|
|
||||||
|
The default value is 0.9.
|
||||||
|
|
||||||
|
\param factor Wheel factor
|
||||||
|
\sa wheelFactor(), setWheelButtonState(),
|
||||||
|
setMouseFactor(), setKeyFactor()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setWheelFactor( double factor )
|
||||||
|
{
|
||||||
|
d_data->wheelFactor = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Wheel factor
|
||||||
|
\sa setWheelFactor()
|
||||||
|
*/
|
||||||
|
double QwtMagnifier::wheelFactor() const
|
||||||
|
{
|
||||||
|
return d_data->wheelFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign keyboard modifiers for zooming in/out using the wheel.
|
||||||
|
The default modifiers are Qt::NoModifiers.
|
||||||
|
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
\sa wheelModifiers()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setWheelModifiers( Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->wheelModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Wheel modifiers
|
||||||
|
\sa setWheelModifiers()
|
||||||
|
*/
|
||||||
|
Qt::KeyboardModifiers QwtMagnifier::wheelModifiers() const
|
||||||
|
{
|
||||||
|
return d_data->wheelModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the mouse factor
|
||||||
|
|
||||||
|
The mouse factor defines the ratio between the current range
|
||||||
|
on the parent widget and the zoomed range for each vertical mouse movement.
|
||||||
|
The default value is 0.95.
|
||||||
|
|
||||||
|
\param factor Wheel factor
|
||||||
|
\sa mouseFactor(), setMouseButton(), setWheelFactor(), setKeyFactor()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setMouseFactor( double factor )
|
||||||
|
{
|
||||||
|
d_data->mouseFactor = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Mouse factor
|
||||||
|
\sa setMouseFactor()
|
||||||
|
*/
|
||||||
|
double QwtMagnifier::mouseFactor() const
|
||||||
|
{
|
||||||
|
return d_data->mouseFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the mouse button, that is used for zooming in/out.
|
||||||
|
The default value is Qt::RightButton.
|
||||||
|
|
||||||
|
\param button Button
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
|
||||||
|
\sa getMouseButton()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setMouseButton(
|
||||||
|
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->mouseButton = button;
|
||||||
|
d_data->mouseButtonModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \sa setMouseButton()
|
||||||
|
void QwtMagnifier::getMouseButton(
|
||||||
|
Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const
|
||||||
|
{
|
||||||
|
button = d_data->mouseButton;
|
||||||
|
modifiers = d_data->mouseButtonModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change the key factor
|
||||||
|
|
||||||
|
The key factor defines the ratio between the current range
|
||||||
|
on the parent widget and the zoomed range for each key press of
|
||||||
|
the zoom in/out keys. The default value is 0.9.
|
||||||
|
|
||||||
|
\param factor Key factor
|
||||||
|
\sa keyFactor(), setZoomInKey(), setZoomOutKey(),
|
||||||
|
setWheelFactor, setMouseFactor()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setKeyFactor( double factor )
|
||||||
|
{
|
||||||
|
d_data->keyFactor = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Key factor
|
||||||
|
\sa setKeyFactor()
|
||||||
|
*/
|
||||||
|
double QwtMagnifier::keyFactor() const
|
||||||
|
{
|
||||||
|
return d_data->keyFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the key, that is used for zooming in.
|
||||||
|
The default combination is Qt::Key_Plus + Qt::NoModifier.
|
||||||
|
|
||||||
|
\param key
|
||||||
|
\param modifiers
|
||||||
|
\sa getZoomInKey(), setZoomOutKey()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setZoomInKey( int key,
|
||||||
|
Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->zoomInKey = key;
|
||||||
|
d_data->zoomInKeyModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Retrieve the settings of the zoom in key
|
||||||
|
|
||||||
|
\param key Key code, see Qt::Key
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
|
||||||
|
\sa setZoomInKey()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::getZoomInKey( int &key,
|
||||||
|
Qt::KeyboardModifiers &modifiers ) const
|
||||||
|
{
|
||||||
|
key = d_data->zoomInKey;
|
||||||
|
modifiers = d_data->zoomInKeyModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assign the key, that is used for zooming out.
|
||||||
|
The default combination is Qt::Key_Minus + Qt::NoModifier.
|
||||||
|
|
||||||
|
\param key
|
||||||
|
\param modifiers
|
||||||
|
\sa getZoomOutKey(), setZoomOutKey()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::setZoomOutKey( int key,
|
||||||
|
Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->zoomOutKey = key;
|
||||||
|
d_data->zoomOutKeyModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Retrieve the settings of the zoom out key
|
||||||
|
|
||||||
|
\param key Key code, see Qt::Key
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
|
||||||
|
\sa setZoomOutKey()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::getZoomOutKey( int &key,
|
||||||
|
Qt::KeyboardModifiers &modifiers ) const
|
||||||
|
{
|
||||||
|
key = d_data->zoomOutKey;
|
||||||
|
modifiers = d_data->zoomOutKeyModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Event filter
|
||||||
|
|
||||||
|
When isEnabled() is true, the mouse events of the
|
||||||
|
observed widget are filtered.
|
||||||
|
|
||||||
|
\param object Object to be filtered
|
||||||
|
\param event Event
|
||||||
|
|
||||||
|
\return Forwarded to QObject::eventFilter()
|
||||||
|
|
||||||
|
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||||
|
widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent()
|
||||||
|
widgetKeyReleaseEvent()
|
||||||
|
*/
|
||||||
|
bool QwtMagnifier::eventFilter( QObject *object, QEvent *event )
|
||||||
|
{
|
||||||
|
if ( object && object == parent() )
|
||||||
|
{
|
||||||
|
switch ( event->type() )
|
||||||
|
{
|
||||||
|
case QEvent::MouseButtonPress:
|
||||||
|
{
|
||||||
|
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::MouseMove:
|
||||||
|
{
|
||||||
|
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::MouseButtonRelease:
|
||||||
|
{
|
||||||
|
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::Wheel:
|
||||||
|
{
|
||||||
|
widgetWheelEvent( static_cast<QWheelEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::KeyPress:
|
||||||
|
{
|
||||||
|
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::KeyRelease:
|
||||||
|
{
|
||||||
|
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter( object, event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse press event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
\sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
if ( parentWidget() == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( ( mouseEvent->button() != d_data->mouseButton ) ||
|
||||||
|
( mouseEvent->modifiers() != d_data->mouseButtonModifiers ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->hasMouseTracking = parentWidget()->hasMouseTracking();
|
||||||
|
|
||||||
|
parentWidget()->setMouseTracking( true );
|
||||||
|
d_data->mousePos = mouseEvent->pos();
|
||||||
|
d_data->mousePressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse release event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
|
||||||
|
\sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(),
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
Q_UNUSED( mouseEvent );
|
||||||
|
|
||||||
|
if ( d_data->mousePressed && parentWidget() )
|
||||||
|
{
|
||||||
|
d_data->mousePressed = false;
|
||||||
|
parentWidget()->setMouseTracking( d_data->hasMouseTracking );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse move event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
if ( !d_data->mousePressed )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int dy = mouseEvent->pos().y() - d_data->mousePos.y();
|
||||||
|
if ( dy != 0 )
|
||||||
|
{
|
||||||
|
double f = d_data->mouseFactor;
|
||||||
|
if ( dy < 0 )
|
||||||
|
f = 1 / f;
|
||||||
|
|
||||||
|
rescale( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
d_data->mousePos = mouseEvent->pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a wheel event for the observed widget.
|
||||||
|
|
||||||
|
\param wheelEvent Wheel event
|
||||||
|
\sa eventFilter()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent )
|
||||||
|
{
|
||||||
|
if ( wheelEvent->modifiers() != d_data->wheelModifiers )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_data->wheelFactor != 0.0 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
A positive delta indicates that the wheel was
|
||||||
|
rotated forwards away from the user; a negative
|
||||||
|
value indicates that the wheel was rotated
|
||||||
|
backwards toward the user.
|
||||||
|
Most mouse types work in steps of 15 degrees,
|
||||||
|
in which case the delta value is a multiple
|
||||||
|
of 120 (== 15 * 8).
|
||||||
|
*/
|
||||||
|
double f = qPow( d_data->wheelFactor,
|
||||||
|
qAbs( wheelEvent->delta() / 120.0 ) );
|
||||||
|
|
||||||
|
if ( wheelEvent->delta() > 0 )
|
||||||
|
f = 1 / f;
|
||||||
|
|
||||||
|
rescale( f );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a key press event for the observed widget.
|
||||||
|
|
||||||
|
\param keyEvent Key event
|
||||||
|
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetKeyPressEvent( QKeyEvent *keyEvent )
|
||||||
|
{
|
||||||
|
if ( keyEvent->key() == d_data->zoomInKey &&
|
||||||
|
keyEvent->modifiers() == d_data->zoomInKeyModifiers )
|
||||||
|
{
|
||||||
|
rescale( d_data->keyFactor );
|
||||||
|
}
|
||||||
|
else if ( keyEvent->key() == d_data->zoomOutKey &&
|
||||||
|
keyEvent->modifiers() == d_data->zoomOutKeyModifiers )
|
||||||
|
{
|
||||||
|
rescale( 1.0 / d_data->keyFactor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a key release event for the observed widget.
|
||||||
|
|
||||||
|
\param keyEvent Key event
|
||||||
|
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||||
|
*/
|
||||||
|
void QwtMagnifier::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
|
||||||
|
{
|
||||||
|
Q_UNUSED( keyEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Parent widget, where the rescaling happens
|
||||||
|
QWidget *QwtMagnifier::parentWidget()
|
||||||
|
{
|
||||||
|
return qobject_cast<QWidget *>( parent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Parent widget, where the rescaling happens
|
||||||
|
const QWidget *QwtMagnifier::parentWidget() const
|
||||||
|
{
|
||||||
|
return qobject_cast<const QWidget *>( parent() );
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_MAGNIFIER_H
|
||||||
|
#define QWT_MAGNIFIER_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qobject.h>
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
|
class QMouseEvent;
|
||||||
|
class QWheelEvent;
|
||||||
|
class QKeyEvent;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief QwtMagnifier provides zooming, by magnifying in steps.
|
||||||
|
|
||||||
|
Using QwtMagnifier a plot can be zoomed in/out in steps using
|
||||||
|
keys, the mouse wheel or moving a mouse button in vertical direction.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtMagnifier: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QwtMagnifier( QWidget * );
|
||||||
|
virtual ~QwtMagnifier();
|
||||||
|
|
||||||
|
QWidget *parentWidget();
|
||||||
|
const QWidget *parentWidget() const;
|
||||||
|
|
||||||
|
void setEnabled( bool );
|
||||||
|
bool isEnabled() const;
|
||||||
|
|
||||||
|
// mouse
|
||||||
|
void setMouseFactor( double );
|
||||||
|
double mouseFactor() const;
|
||||||
|
|
||||||
|
void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||||
|
void getMouseButton( Qt::MouseButton &, Qt::KeyboardModifiers & ) const;
|
||||||
|
|
||||||
|
// mouse wheel
|
||||||
|
void setWheelFactor( double );
|
||||||
|
double wheelFactor() const;
|
||||||
|
|
||||||
|
void setWheelModifiers( Qt::KeyboardModifiers );
|
||||||
|
Qt::KeyboardModifiers wheelModifiers() const;
|
||||||
|
|
||||||
|
// keyboard
|
||||||
|
void setKeyFactor( double );
|
||||||
|
double keyFactor() const;
|
||||||
|
|
||||||
|
void setZoomInKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||||
|
void getZoomInKey( int &key, Qt::KeyboardModifiers & ) const;
|
||||||
|
|
||||||
|
void setZoomOutKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||||
|
void getZoomOutKey( int &key, Qt::KeyboardModifiers & ) const;
|
||||||
|
|
||||||
|
virtual bool eventFilter( QObject *, QEvent * );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
Rescale the parent widget
|
||||||
|
\param factor Scale factor
|
||||||
|
*/
|
||||||
|
virtual void rescale( double factor ) = 0;
|
||||||
|
|
||||||
|
virtual void widgetMousePressEvent( QMouseEvent * );
|
||||||
|
virtual void widgetMouseReleaseEvent( QMouseEvent * );
|
||||||
|
virtual void widgetMouseMoveEvent( QMouseEvent * );
|
||||||
|
virtual void widgetWheelEvent( QWheelEvent * );
|
||||||
|
virtual void widgetKeyPressEvent( QKeyEvent * );
|
||||||
|
virtual void widgetKeyReleaseEvent( QKeyEvent * );
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/* -*- 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 "qwt_math.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Find the smallest value in an array
|
||||||
|
\param array Pointer to an array
|
||||||
|
\param size Array size
|
||||||
|
*/
|
||||||
|
double qwtGetMin( const double *array, int size )
|
||||||
|
{
|
||||||
|
if ( size <= 0 )
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
double rv = array[0];
|
||||||
|
for ( int i = 1; i < size; i++ )
|
||||||
|
rv = qMin( rv, array[i] );
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Find the largest value in an array
|
||||||
|
\param array Pointer to an array
|
||||||
|
\param size Array size
|
||||||
|
*/
|
||||||
|
double qwtGetMax( const double *array, int size )
|
||||||
|
{
|
||||||
|
if ( size <= 0 )
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
double rv = array[0];
|
||||||
|
for ( int i = 1; i < size; i++ )
|
||||||
|
rv = qMax( rv, array[i] );
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Normalize an angle to be int the range [0.0, 2 * PI[
|
||||||
|
\param radians Angle in radians
|
||||||
|
\return Normalized angle in radians
|
||||||
|
*/
|
||||||
|
double qwtNormalizeRadians( double radians )
|
||||||
|
{
|
||||||
|
double a = ::fmod( radians, 2.0 * M_PI );
|
||||||
|
if ( a < 0.0 )
|
||||||
|
a += 2.0 * M_PI;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Normalize an angle to be int the range [0.0, 360.0[
|
||||||
|
\param radians Angle in degrees
|
||||||
|
\return Normalized angle in degrees
|
||||||
|
*/
|
||||||
|
double qwtNormalizeDegrees( double degrees )
|
||||||
|
{
|
||||||
|
double a = ::fmod( degrees, 360.0 );
|
||||||
|
if ( a < 0.0 )
|
||||||
|
a += 360.0;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_MATH_H
|
||||||
|
#define QWT_MATH_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/*
|
||||||
|
Microsoft says:
|
||||||
|
|
||||||
|
Define _USE_MATH_DEFINES before including math.h to expose these macro
|
||||||
|
definitions for common math constants. These are placed under an #ifdef
|
||||||
|
since these commonly-defined names are not part of the C/C++ standards.
|
||||||
|
*/
|
||||||
|
#define _USE_MATH_DEFINES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <qmath.h>
|
||||||
|
#include "qwt_global.h"
|
||||||
|
|
||||||
|
#ifndef M_PI_2
|
||||||
|
// For Qt <= 4.8.4 M_PI_2 is not known by MinGW-w64
|
||||||
|
// when compiling with -std=c++11
|
||||||
|
#define M_PI_2 (1.57079632679489661923)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOG_MIN
|
||||||
|
//! Minimum value for logarithmic scales
|
||||||
|
#define LOG_MIN 1.0e-100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOG_MAX
|
||||||
|
//! Maximum value for logarithmic scales
|
||||||
|
#define LOG_MAX 1.0e100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QWT_EXPORT double qwtGetMin( const double *array, int size );
|
||||||
|
QWT_EXPORT double qwtGetMax( const double *array, int size );
|
||||||
|
|
||||||
|
QWT_EXPORT double qwtNormalizeRadians( double radians );
|
||||||
|
QWT_EXPORT double qwtNormalizeDegrees( double degrees );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Compare 2 values, relative to an interval
|
||||||
|
|
||||||
|
Values are "equal", when :
|
||||||
|
\f$\cdot value2 - value1 <= abs(intervalSize * 10e^{-6})\f$
|
||||||
|
|
||||||
|
\param value1 First value to compare
|
||||||
|
\param value2 Second value to compare
|
||||||
|
\param intervalSize interval size
|
||||||
|
|
||||||
|
\return 0: if equal, -1: if value2 > value1, 1: if value1 > value2
|
||||||
|
*/
|
||||||
|
inline int qwtFuzzyCompare( double value1, double value2, double intervalSize )
|
||||||
|
{
|
||||||
|
const double eps = qAbs( 1.0e-6 * intervalSize );
|
||||||
|
|
||||||
|
if ( value2 - value1 > eps )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ( value1 - value2 > eps )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool qwtFuzzyGreaterOrEqual( double d1, double d2 )
|
||||||
|
{
|
||||||
|
return ( d1 >= d2 ) || qFuzzyCompare( d1, d2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool qwtFuzzyLessOrEqual( double d1, double d2 )
|
||||||
|
{
|
||||||
|
return ( d1 <= d2 ) || qFuzzyCompare( d1, d2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return the sign
|
||||||
|
inline int qwtSign( double x )
|
||||||
|
{
|
||||||
|
if ( x > 0.0 )
|
||||||
|
return 1;
|
||||||
|
else if ( x < 0.0 )
|
||||||
|
return ( -1 );
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return the square of a number
|
||||||
|
inline double qwtSqr( double x )
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Approximation of arc tangent ( error below 0,005 radians )
|
||||||
|
inline double qwtFastAtan( double x )
|
||||||
|
{
|
||||||
|
if ( x < -1.0 )
|
||||||
|
return -M_PI_2 - x / ( x * x + 0.28 );
|
||||||
|
|
||||||
|
if ( x > 1.0 )
|
||||||
|
return M_PI_2 - x / ( x * x + 0.28 );
|
||||||
|
|
||||||
|
return x / ( 1.0 + x * x * 0.28 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Approximation of arc tangent ( error below 0,005 radians )
|
||||||
|
inline double qwtFastAtan2( double y, double x )
|
||||||
|
{
|
||||||
|
if ( x > 0 )
|
||||||
|
return qwtFastAtan( y / x );
|
||||||
|
|
||||||
|
if ( x < 0 )
|
||||||
|
{
|
||||||
|
const double d = qwtFastAtan( y / x );
|
||||||
|
return ( y >= 0 ) ? d + M_PI : d - M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( y < 0.0 )
|
||||||
|
return -M_PI_2;
|
||||||
|
|
||||||
|
if ( y > 0.0 )
|
||||||
|
return M_PI_2;
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Translate degrees into radians
|
||||||
|
inline double qwtRadians( double degrees )
|
||||||
|
{
|
||||||
|
return degrees * M_PI / 180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Translate radians into degrees
|
||||||
|
inline double qwtDegrees( double degrees )
|
||||||
|
{
|
||||||
|
return degrees * 180.0 / M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,298 @@
|
|||||||
|
/* -*- 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 "qwt_matrix_raster_data.h"
|
||||||
|
#include <qnumeric.h>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
|
class QwtMatrixRasterData::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
resampleMode(QwtMatrixRasterData::NearestNeighbour),
|
||||||
|
numColumns(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double value(int row, int col) const
|
||||||
|
{
|
||||||
|
return values.data()[ row * numColumns + col ];
|
||||||
|
}
|
||||||
|
|
||||||
|
QwtMatrixRasterData::ResampleMode resampleMode;
|
||||||
|
|
||||||
|
QVector<double> values;
|
||||||
|
int numColumns;
|
||||||
|
int numRows;
|
||||||
|
|
||||||
|
double dx;
|
||||||
|
double dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
QwtMatrixRasterData::QwtMatrixRasterData()
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtMatrixRasterData::~QwtMatrixRasterData()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Set the resampling algorithm
|
||||||
|
|
||||||
|
\param mode Resampling mode
|
||||||
|
\sa resampleMode(), value()
|
||||||
|
*/
|
||||||
|
void QwtMatrixRasterData::setResampleMode( ResampleMode mode )
|
||||||
|
{
|
||||||
|
d_data->resampleMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return resampling algorithm
|
||||||
|
\sa setResampleMode(), value()
|
||||||
|
*/
|
||||||
|
QwtMatrixRasterData::ResampleMode QwtMatrixRasterData::resampleMode() const
|
||||||
|
{
|
||||||
|
return d_data->resampleMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Assign the bounding interval for an axis
|
||||||
|
|
||||||
|
Setting the bounding intervals for the X/Y axis is mandatory
|
||||||
|
to define the positions for the values of the value matrix.
|
||||||
|
The interval in Z direction defines the possible range for
|
||||||
|
the values in the matrix, what is f.e used by QwtPlotSpectrogram
|
||||||
|
to map values to colors. The Z-interval might be the bounding
|
||||||
|
interval of the values in the matrix, but usually it isn't.
|
||||||
|
( f.e a interval of 0.0-100.0 for values in percentage )
|
||||||
|
|
||||||
|
\param axis X, Y or Z axis
|
||||||
|
\param interval Interval
|
||||||
|
|
||||||
|
\sa QwtRasterData::interval(), setValueMatrix()
|
||||||
|
*/
|
||||||
|
void QwtMatrixRasterData::setInterval(
|
||||||
|
Qt::Axis axis, const QwtInterval &interval )
|
||||||
|
{
|
||||||
|
QwtRasterData::setInterval( axis, interval );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Assign a value matrix
|
||||||
|
|
||||||
|
The positions of the values are calculated by dividing
|
||||||
|
the bounding rectangle of the X/Y intervals into equidistant
|
||||||
|
rectangles ( pixels ). Each value corresponds to the center of
|
||||||
|
a pixel.
|
||||||
|
|
||||||
|
\param values Vector of values
|
||||||
|
\param numColumns Number of columns
|
||||||
|
|
||||||
|
\sa valueMatrix(), numColumns(), numRows(), setInterval()()
|
||||||
|
*/
|
||||||
|
void QwtMatrixRasterData::setValueMatrix(
|
||||||
|
const QVector<double> &values, int numColumns )
|
||||||
|
{
|
||||||
|
d_data->values = values;
|
||||||
|
d_data->numColumns = qMax( numColumns, 0 );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Value matrix
|
||||||
|
\sa setValueMatrix(), numColumns(), numRows(), setInterval()
|
||||||
|
*/
|
||||||
|
const QVector<double> QwtMatrixRasterData::valueMatrix() const
|
||||||
|
{
|
||||||
|
return d_data->values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Change a single value in the matrix
|
||||||
|
|
||||||
|
\param row Row index
|
||||||
|
\param col Column index
|
||||||
|
\param value New value
|
||||||
|
|
||||||
|
\sa value(), setValueMatrix()
|
||||||
|
*/
|
||||||
|
void QwtMatrixRasterData::setValue( int row, int col, double value )
|
||||||
|
{
|
||||||
|
if ( row >= 0 && row < d_data->numRows &&
|
||||||
|
col >= 0 && col < d_data->numColumns )
|
||||||
|
{
|
||||||
|
const int index = row * d_data->numColumns + col;
|
||||||
|
d_data->values.data()[ index ] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of columns of the value matrix
|
||||||
|
\sa valueMatrix(), numRows(), setValueMatrix()
|
||||||
|
*/
|
||||||
|
int QwtMatrixRasterData::numColumns() const
|
||||||
|
{
|
||||||
|
return d_data->numColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Number of rows of the value matrix
|
||||||
|
\sa valueMatrix(), numColumns(), setValueMatrix()
|
||||||
|
*/
|
||||||
|
int QwtMatrixRasterData::numRows() const
|
||||||
|
{
|
||||||
|
return d_data->numRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Calculate the pixel hint
|
||||||
|
|
||||||
|
pixelHint() returns the geometry of a pixel, that can be used
|
||||||
|
to calculate the resolution and alignment of the plot item, that is
|
||||||
|
representing the data.
|
||||||
|
|
||||||
|
- NearestNeighbour\n
|
||||||
|
pixelHint() returns the surrounding pixel of the top left value
|
||||||
|
in the matrix.
|
||||||
|
|
||||||
|
- BilinearInterpolation\n
|
||||||
|
Returns an empty rectangle recommending
|
||||||
|
to render in target device ( f.e. screen ) resolution.
|
||||||
|
|
||||||
|
\param area Requested area, ignored
|
||||||
|
\return Calculated hint
|
||||||
|
|
||||||
|
\sa ResampleMode, setMatrix(), setInterval()
|
||||||
|
*/
|
||||||
|
QRectF QwtMatrixRasterData::pixelHint( const QRectF &area ) const
|
||||||
|
{
|
||||||
|
Q_UNUSED( area )
|
||||||
|
|
||||||
|
QRectF rect;
|
||||||
|
if ( d_data->resampleMode == NearestNeighbour )
|
||||||
|
{
|
||||||
|
const QwtInterval intervalX = interval( Qt::XAxis );
|
||||||
|
const QwtInterval intervalY = interval( Qt::YAxis );
|
||||||
|
if ( intervalX.isValid() && intervalY.isValid() )
|
||||||
|
{
|
||||||
|
rect = QRectF( intervalX.minValue(), intervalY.minValue(),
|
||||||
|
d_data->dx, d_data->dy );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the value at a raster position
|
||||||
|
|
||||||
|
\param x X value in plot coordinates
|
||||||
|
\param y Y value in plot coordinates
|
||||||
|
|
||||||
|
\sa ResampleMode
|
||||||
|
*/
|
||||||
|
double QwtMatrixRasterData::value( double x, double y ) const
|
||||||
|
{
|
||||||
|
const QwtInterval xInterval = interval( Qt::XAxis );
|
||||||
|
const QwtInterval yInterval = interval( Qt::YAxis );
|
||||||
|
|
||||||
|
if ( !( xInterval.contains(x) && yInterval.contains(y) ) )
|
||||||
|
return qQNaN();
|
||||||
|
|
||||||
|
double value;
|
||||||
|
|
||||||
|
switch( d_data->resampleMode )
|
||||||
|
{
|
||||||
|
case BilinearInterpolation:
|
||||||
|
{
|
||||||
|
int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1;
|
||||||
|
int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1;
|
||||||
|
int col2 = col1 + 1;
|
||||||
|
int row2 = row1 + 1;
|
||||||
|
|
||||||
|
if ( col1 < 0 )
|
||||||
|
col1 = col2;
|
||||||
|
else if ( col2 >= static_cast<int>( d_data->numColumns ) )
|
||||||
|
col2 = col1;
|
||||||
|
|
||||||
|
if ( row1 < 0 )
|
||||||
|
row1 = row2;
|
||||||
|
else if ( row2 >= static_cast<int>( d_data->numRows ) )
|
||||||
|
row2 = row1;
|
||||||
|
|
||||||
|
const double v11 = d_data->value( row1, col1 );
|
||||||
|
const double v21 = d_data->value( row1, col2 );
|
||||||
|
const double v12 = d_data->value( row2, col1 );
|
||||||
|
const double v22 = d_data->value( row2, col2 );
|
||||||
|
|
||||||
|
const double x2 = xInterval.minValue() +
|
||||||
|
( col2 + 0.5 ) * d_data->dx;
|
||||||
|
const double y2 = yInterval.minValue() +
|
||||||
|
( row2 + 0.5 ) * d_data->dy;
|
||||||
|
|
||||||
|
const double rx = ( x2 - x ) / d_data->dx;
|
||||||
|
const double ry = ( y2 - y ) / d_data->dy;
|
||||||
|
|
||||||
|
const double vr1 = rx * v11 + ( 1.0 - rx ) * v21;
|
||||||
|
const double vr2 = rx * v12 + ( 1.0 - rx ) * v22;
|
||||||
|
|
||||||
|
value = ry * vr1 + ( 1.0 - ry ) * vr2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NearestNeighbour:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int row = int( (y - yInterval.minValue() ) / d_data->dy );
|
||||||
|
int col = int( (x - xInterval.minValue() ) / d_data->dx );
|
||||||
|
|
||||||
|
// In case of intervals, where the maximum is included
|
||||||
|
// we get out of bound for row/col, when the value for the
|
||||||
|
// maximum is requested. Instead we return the value
|
||||||
|
// from the last row/col
|
||||||
|
|
||||||
|
if ( row >= d_data->numRows )
|
||||||
|
row = d_data->numRows - 1;
|
||||||
|
|
||||||
|
if ( col >= d_data->numColumns )
|
||||||
|
col = d_data->numColumns - 1;
|
||||||
|
|
||||||
|
value = d_data->value( row, col );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtMatrixRasterData::update()
|
||||||
|
{
|
||||||
|
d_data->numRows = 0;
|
||||||
|
d_data->dx = 0.0;
|
||||||
|
d_data->dy = 0.0;
|
||||||
|
|
||||||
|
if ( d_data->numColumns > 0 )
|
||||||
|
{
|
||||||
|
d_data->numRows = d_data->values.size() / d_data->numColumns;
|
||||||
|
|
||||||
|
const QwtInterval xInterval = interval( Qt::XAxis );
|
||||||
|
const QwtInterval yInterval = interval( Qt::YAxis );
|
||||||
|
if ( xInterval.isValid() )
|
||||||
|
d_data->dx = xInterval.width() / d_data->numColumns;
|
||||||
|
if ( yInterval.isValid() )
|
||||||
|
d_data->dy = yInterval.width() / d_data->numRows;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_MATRIX_RASTER_DATA_H
|
||||||
|
#define QWT_MATRIX_RASTER_DATA_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include "qwt_raster_data.h"
|
||||||
|
#include <qvector.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A class representing a matrix of values as raster data
|
||||||
|
|
||||||
|
QwtMatrixRasterData implements an interface for a matrix of
|
||||||
|
equidistant values, that can be used by a QwtPlotRasterItem.
|
||||||
|
It implements a couple of resampling algorithms, to provide
|
||||||
|
values for positions, that or not on the value matrix.
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtMatrixRasterData: public QwtRasterData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
\brief Resampling algorithm
|
||||||
|
The default setting is NearestNeighbour;
|
||||||
|
*/
|
||||||
|
enum ResampleMode
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
Return the value from the matrix, that is nearest to the
|
||||||
|
the requested position.
|
||||||
|
*/
|
||||||
|
NearestNeighbour,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Interpolate the value from the distances and values of the
|
||||||
|
4 surrounding values in the matrix,
|
||||||
|
*/
|
||||||
|
BilinearInterpolation
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtMatrixRasterData();
|
||||||
|
virtual ~QwtMatrixRasterData();
|
||||||
|
|
||||||
|
void setResampleMode(ResampleMode mode);
|
||||||
|
ResampleMode resampleMode() const;
|
||||||
|
|
||||||
|
virtual void setInterval( Qt::Axis, const QwtInterval & );
|
||||||
|
|
||||||
|
void setValueMatrix( const QVector<double> &values, int numColumns );
|
||||||
|
const QVector<double> valueMatrix() const;
|
||||||
|
|
||||||
|
void setValue( int row, int col, double value );
|
||||||
|
|
||||||
|
int numColumns() const;
|
||||||
|
int numRows() const;
|
||||||
|
|
||||||
|
virtual QRectF pixelHint( const QRectF & ) const;
|
||||||
|
|
||||||
|
virtual double value( double x, double y ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_NULL_PAINT_DEVICE_H
|
||||||
|
#define QWT_NULL_PAINT_DEVICE_H 1
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
#include <qpaintdevice.h>
|
||||||
|
#include <qpaintengine.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A null paint device doing nothing
|
||||||
|
|
||||||
|
Sometimes important layout/rendering geometries are not
|
||||||
|
available or changeable from the public Qt class interface.
|
||||||
|
( f.e hidden in the style implementation ).
|
||||||
|
|
||||||
|
QwtNullPaintDevice can be used to manipulate or filter out
|
||||||
|
this information by analyzing the stream of paint primitives.
|
||||||
|
|
||||||
|
F.e. QwtNullPaintDevice is used by QwtPlotCanvas to identify
|
||||||
|
styled backgrounds with rounded corners.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class QWT_EXPORT QwtNullPaintDevice: public QPaintDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
\brief Render mode
|
||||||
|
|
||||||
|
\sa setMode(), mode()
|
||||||
|
*/
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
All vector graphic primitives are painted by
|
||||||
|
the corresponding draw methods
|
||||||
|
*/
|
||||||
|
NormalMode,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Vector graphic primitives ( beside polygons ) are mapped to a QPainterPath
|
||||||
|
and are painted by drawPath. In PathMode mode
|
||||||
|
only a few draw methods are called:
|
||||||
|
|
||||||
|
- drawPath()
|
||||||
|
- drawPixmap()
|
||||||
|
- drawImage()
|
||||||
|
- drawPolygon()
|
||||||
|
*/
|
||||||
|
PolygonPathMode,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Vector graphic primitives are mapped to a QPainterPath
|
||||||
|
and are painted by drawPath. In PathMode mode
|
||||||
|
only a few draw methods are called:
|
||||||
|
|
||||||
|
- drawPath()
|
||||||
|
- drawPixmap()
|
||||||
|
- drawImage()
|
||||||
|
*/
|
||||||
|
PathMode
|
||||||
|
};
|
||||||
|
|
||||||
|
QwtNullPaintDevice();
|
||||||
|
virtual ~QwtNullPaintDevice();
|
||||||
|
|
||||||
|
void setMode( Mode );
|
||||||
|
Mode mode() const;
|
||||||
|
|
||||||
|
virtual QPaintEngine *paintEngine() const;
|
||||||
|
|
||||||
|
virtual int metric( PaintDeviceMetric ) const;
|
||||||
|
|
||||||
|
virtual void drawRects(const QRect *, int );
|
||||||
|
virtual void drawRects(const QRectF *, int );
|
||||||
|
|
||||||
|
virtual void drawLines(const QLine *, int );
|
||||||
|
virtual void drawLines(const QLineF *, int );
|
||||||
|
|
||||||
|
virtual void drawEllipse(const QRectF &);
|
||||||
|
virtual void drawEllipse(const QRect &);
|
||||||
|
|
||||||
|
virtual void drawPath(const QPainterPath &);
|
||||||
|
|
||||||
|
virtual void drawPoints(const QPointF *, int );
|
||||||
|
virtual void drawPoints(const QPoint *, int );
|
||||||
|
|
||||||
|
virtual void drawPolygon(
|
||||||
|
const QPointF *, int , QPaintEngine::PolygonDrawMode );
|
||||||
|
|
||||||
|
virtual void drawPolygon(
|
||||||
|
const QPoint *, int , QPaintEngine::PolygonDrawMode );
|
||||||
|
|
||||||
|
virtual void drawPixmap(const QRectF &,
|
||||||
|
const QPixmap &, const QRectF &);
|
||||||
|
|
||||||
|
virtual void drawTextItem(const QPointF &, const QTextItem &);
|
||||||
|
|
||||||
|
virtual void drawTiledPixmap(const QRectF &,
|
||||||
|
const QPixmap &, const QPointF & );
|
||||||
|
|
||||||
|
virtual void drawImage(const QRectF &,
|
||||||
|
const QImage &, const QRectF &, Qt::ImageConversionFlags );
|
||||||
|
|
||||||
|
virtual void updateState( const QPaintEngineState & );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! \return Size needed to implement metric()
|
||||||
|
virtual QSize sizeMetrics() const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PaintEngine;
|
||||||
|
PaintEngine *d_engine;
|
||||||
|
|
||||||
|
class PrivateData;
|
||||||
|
PrivateData *d_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
/* -*- 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
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWT_PAINTER_H
|
||||||
|
#define QWT_PAINTER_H
|
||||||
|
|
||||||
|
#include "qwt_global.h"
|
||||||
|
|
||||||
|
#include <qpoint.h>
|
||||||
|
#include <qrect.h>
|
||||||
|
#include <qpen.h>
|
||||||
|
#include <qline.h>
|
||||||
|
#include <qpalette.h>
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
class QBrush;
|
||||||
|
class QColor;
|
||||||
|
class QWidget;
|
||||||
|
class QPolygonF;
|
||||||
|
class QRectF;
|
||||||
|
class QImage;
|
||||||
|
class QPixmap;
|
||||||
|
class QwtScaleMap;
|
||||||
|
class QwtColorMap;
|
||||||
|
class QwtInterval;
|
||||||
|
|
||||||
|
class QTextDocument;
|
||||||
|
class QPainterPath;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief A collection of QPainter workarounds
|
||||||
|
*/
|
||||||
|
class QWT_EXPORT QwtPainter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void setPolylineSplitting( bool );
|
||||||
|
static bool polylineSplitting();
|
||||||
|
|
||||||
|
static void setRoundingAlignment( bool );
|
||||||
|
static bool roundingAlignment();
|
||||||
|
static bool roundingAlignment(QPainter *);
|
||||||
|
|
||||||
|
static void drawText( QPainter *, double x, double y, const QString & );
|
||||||
|
static void drawText( QPainter *, const QPointF &, const QString & );
|
||||||
|
static void drawText( QPainter *, double x, double y, double w, double h,
|
||||||
|
int flags, const QString & );
|
||||||
|
static void drawText( QPainter *, const QRectF &,
|
||||||
|
int flags, const QString & );
|
||||||
|
|
||||||
|
#ifndef QT_NO_RICHTEXT
|
||||||
|
static void drawSimpleRichText( QPainter *, const QRectF &,
|
||||||
|
int flags, const QTextDocument & );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void drawRect( QPainter *, double x, double y, double w, double h );
|
||||||
|
static void drawRect( QPainter *, const QRectF &rect );
|
||||||
|
static void fillRect( QPainter *, const QRectF &, const QBrush & );
|
||||||
|
|
||||||
|
static void drawEllipse( QPainter *, const QRectF & );
|
||||||
|
static void drawPie( QPainter *, const QRectF &, int a, int alen );
|
||||||
|
|
||||||
|
static void drawLine( QPainter *, double x1, double y1, double x2, double y2 );
|
||||||
|
static void drawLine( QPainter *, const QPointF &p1, const QPointF &p2 );
|
||||||
|
static void drawLine( QPainter *, const QLineF & );
|
||||||
|
|
||||||
|
static void drawPolygon( QPainter *, const QPolygonF & );
|
||||||
|
static void drawPolyline( QPainter *, const QPolygonF & );
|
||||||
|
static void drawPolyline( QPainter *, const QPointF *, int pointCount );
|
||||||
|
|
||||||
|
static void drawPolygon( QPainter *, const QPolygon & );
|
||||||
|
static void drawPolyline( QPainter *, const QPolygon & );
|
||||||
|
static void drawPolyline( QPainter *, const QPoint *, int pointCount );
|
||||||
|
|
||||||
|
static void drawPoint( QPainter *, const QPoint & );
|
||||||
|
static void drawPoints( QPainter *, const QPolygon & );
|
||||||
|
static void drawPoints( QPainter *, const QPoint *, int pointCount );
|
||||||
|
|
||||||
|
static void drawPoint( QPainter *, double x, double y );
|
||||||
|
static void drawPoint( QPainter *, const QPointF & );
|
||||||
|
static void drawPoints( QPainter *, const QPolygonF & );
|
||||||
|
static void drawPoints( QPainter *, const QPointF *, int pointCount );
|
||||||
|
|
||||||
|
static void drawPath( QPainter *, const QPainterPath & );
|
||||||
|
static void drawImage( QPainter *, const QRectF &, const QImage & );
|
||||||
|
static void drawPixmap( QPainter *, const QRectF &, const QPixmap & );
|
||||||
|
|
||||||
|
static void drawRoundFrame( QPainter *,
|
||||||
|
const QRectF &, const QPalette &, int lineWidth, int frameStyle );
|
||||||
|
|
||||||
|
static void drawRoundedFrame( QPainter *,
|
||||||
|
const QRectF &, double xRadius, double yRadius,
|
||||||
|
const QPalette &, int lineWidth, int frameStyle );
|
||||||
|
|
||||||
|
static void drawFrame( QPainter *, const QRectF &rect,
|
||||||
|
const QPalette &palette, QPalette::ColorRole foregroundRole,
|
||||||
|
int frameWidth, int midLineWidth, int frameStyle );
|
||||||
|
|
||||||
|
static void drawFocusRect( QPainter *, const QWidget * );
|
||||||
|
static void drawFocusRect( QPainter *, const QWidget *, const QRect & );
|
||||||
|
|
||||||
|
static void drawColorBar( QPainter *painter,
|
||||||
|
const QwtColorMap &, const QwtInterval &,
|
||||||
|
const QwtScaleMap &, Qt::Orientation, const QRectF & );
|
||||||
|
|
||||||
|
static bool isAligning( QPainter *painter );
|
||||||
|
static bool isX11GraphicsSystem();
|
||||||
|
|
||||||
|
static void fillPixmap( const QWidget *,
|
||||||
|
QPixmap &, const QPoint &offset = QPoint() );
|
||||||
|
|
||||||
|
static void drawBackgound( QPainter *painter,
|
||||||
|
const QRectF &rect, const QWidget *widget );
|
||||||
|
|
||||||
|
static QPixmap backingStore( QWidget *, const QSize & );
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool d_polylineSplitting;
|
||||||
|
static bool d_roundingAlignment;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Wrapper for QPainter::drawPoint()
|
||||||
|
inline void QwtPainter::drawPoint( QPainter *painter, double x, double y )
|
||||||
|
{
|
||||||
|
QwtPainter::drawPoint( painter, QPointF( x, y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Wrapper for QPainter::drawPoints()
|
||||||
|
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygon &polygon )
|
||||||
|
{
|
||||||
|
drawPoints( painter, polygon.data(), polygon.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Wrapper for QPainter::drawPoints()
|
||||||
|
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygonF &polygon )
|
||||||
|
{
|
||||||
|
drawPoints( painter, polygon.data(), polygon.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Wrapper for QPainter::drawLine()
|
||||||
|
inline void QwtPainter::drawLine( QPainter *painter,
|
||||||
|
double x1, double y1, double x2, double y2 )
|
||||||
|
{
|
||||||
|
QwtPainter::drawLine( painter, QPointF( x1, y1 ), QPointF( x2, y2 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Wrapper for QPainter::drawLine()
|
||||||
|
inline void QwtPainter::drawLine( QPainter *painter, const QLineF &line )
|
||||||
|
{
|
||||||
|
QwtPainter::drawLine( painter, line.p1(), line.p2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True, when line splitting for the raster paint engine is enabled.
|
||||||
|
\sa setPolylineSplitting()
|
||||||
|
*/
|
||||||
|
inline bool QwtPainter::polylineSplitting()
|
||||||
|
{
|
||||||
|
return d_polylineSplitting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Check whether coordinates should be rounded, before they are painted
|
||||||
|
to a paint engine that rounds to integer values. For other paint engines
|
||||||
|
( PDF, SVG ), this flag has no effect.
|
||||||
|
|
||||||
|
\return True, when rounding is enabled
|
||||||
|
\sa setRoundingAlignment(), isAligning()
|
||||||
|
*/
|
||||||
|
inline bool QwtPainter::roundingAlignment()
|
||||||
|
{
|
||||||
|
return d_roundingAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return roundingAlignment() && isAligning(painter);
|
||||||
|
\param painter Painter
|
||||||
|
*/
|
||||||
|
inline bool QwtPainter::roundingAlignment(QPainter *painter)
|
||||||
|
{
|
||||||
|
return d_roundingAlignment && isAligning(painter);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,237 @@
|
|||||||
|
/* -*- 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 "qwt_painter_command.h"
|
||||||
|
|
||||||
|
//! Construct an invalid command
|
||||||
|
QwtPainterCommand::QwtPainterCommand():
|
||||||
|
d_type( Invalid )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Copy constructor
|
||||||
|
QwtPainterCommand::QwtPainterCommand( const QPainterPath &path ):
|
||||||
|
d_type( Path )
|
||||||
|
{
|
||||||
|
d_path = new QPainterPath( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor for Pixmap paint operation
|
||||||
|
|
||||||
|
\param rect Target rectangle
|
||||||
|
\param pixmap Pixmap
|
||||||
|
\param subRect Rectangle inside the pixmap
|
||||||
|
|
||||||
|
\sa QPainter::drawPixmap()
|
||||||
|
*/
|
||||||
|
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
|
||||||
|
const QPixmap &pixmap, const QRectF& subRect ):
|
||||||
|
d_type( Pixmap )
|
||||||
|
{
|
||||||
|
d_pixmapData = new PixmapData();
|
||||||
|
d_pixmapData->rect = rect;
|
||||||
|
d_pixmapData->pixmap = pixmap;
|
||||||
|
d_pixmapData->subRect = subRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor for Image paint operation
|
||||||
|
|
||||||
|
\param rect Target rectangle
|
||||||
|
\param image Image
|
||||||
|
\param subRect Rectangle inside the image
|
||||||
|
\param flags Conversion flags
|
||||||
|
|
||||||
|
\sa QPainter::drawImage()
|
||||||
|
*/
|
||||||
|
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
|
||||||
|
const QImage &image, const QRectF& subRect,
|
||||||
|
Qt::ImageConversionFlags flags ):
|
||||||
|
d_type( Image )
|
||||||
|
{
|
||||||
|
d_imageData = new ImageData();
|
||||||
|
d_imageData->rect = rect;
|
||||||
|
d_imageData->image = image;
|
||||||
|
d_imageData->subRect = subRect;
|
||||||
|
d_imageData->flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructor for State paint operation
|
||||||
|
\param state Paint engine state
|
||||||
|
*/
|
||||||
|
QwtPainterCommand::QwtPainterCommand( const QPaintEngineState &state ):
|
||||||
|
d_type( State )
|
||||||
|
{
|
||||||
|
d_stateData = new StateData();
|
||||||
|
|
||||||
|
d_stateData->flags = state.state();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyPen )
|
||||||
|
d_stateData->pen = state.pen();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyBrush )
|
||||||
|
d_stateData->brush = state.brush();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyBrushOrigin )
|
||||||
|
d_stateData->brushOrigin = state.brushOrigin();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyFont )
|
||||||
|
d_stateData->font = state.font();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyBackground )
|
||||||
|
{
|
||||||
|
d_stateData->backgroundMode = state.backgroundMode();
|
||||||
|
d_stateData->backgroundBrush = state.backgroundBrush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyTransform )
|
||||||
|
d_stateData->transform = state.transform();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyClipEnabled )
|
||||||
|
d_stateData->isClipEnabled = state.isClipEnabled();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyClipRegion )
|
||||||
|
{
|
||||||
|
d_stateData->clipRegion = state.clipRegion();
|
||||||
|
d_stateData->clipOperation = state.clipOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyClipPath )
|
||||||
|
{
|
||||||
|
d_stateData->clipPath = state.clipPath();
|
||||||
|
d_stateData->clipOperation = state.clipOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyHints )
|
||||||
|
d_stateData->renderHints = state.renderHints();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyCompositionMode )
|
||||||
|
d_stateData->compositionMode = state.compositionMode();
|
||||||
|
|
||||||
|
if ( d_stateData->flags & QPaintEngine::DirtyOpacity )
|
||||||
|
d_stateData->opacity = state.opacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Copy constructor
|
||||||
|
\param other Command to be copied
|
||||||
|
|
||||||
|
*/
|
||||||
|
QwtPainterCommand::QwtPainterCommand(const QwtPainterCommand &other)
|
||||||
|
{
|
||||||
|
copy( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtPainterCommand::~QwtPainterCommand()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Assignment operator
|
||||||
|
|
||||||
|
\param other Command to be copied
|
||||||
|
\return Modified command
|
||||||
|
*/
|
||||||
|
QwtPainterCommand &QwtPainterCommand::operator=(const QwtPainterCommand &other)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
copy( other );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtPainterCommand::copy( const QwtPainterCommand &other )
|
||||||
|
{
|
||||||
|
d_type = other.d_type;
|
||||||
|
|
||||||
|
switch( other.d_type )
|
||||||
|
{
|
||||||
|
case Path:
|
||||||
|
{
|
||||||
|
d_path = new QPainterPath( *other.d_path );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Pixmap:
|
||||||
|
{
|
||||||
|
d_pixmapData = new PixmapData( *other.d_pixmapData );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Image:
|
||||||
|
{
|
||||||
|
d_imageData = new ImageData( *other.d_imageData );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State:
|
||||||
|
{
|
||||||
|
d_stateData = new StateData( *other.d_stateData );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwtPainterCommand::reset()
|
||||||
|
{
|
||||||
|
switch( d_type )
|
||||||
|
{
|
||||||
|
case Path:
|
||||||
|
{
|
||||||
|
delete d_path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Pixmap:
|
||||||
|
{
|
||||||
|
delete d_pixmapData;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Image:
|
||||||
|
{
|
||||||
|
delete d_imageData;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State:
|
||||||
|
{
|
||||||
|
delete d_stateData;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d_type = Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Painter path to be painted
|
||||||
|
QPainterPath *QwtPainterCommand::path()
|
||||||
|
{
|
||||||
|
return d_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Attributes how to paint a QPixmap
|
||||||
|
QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData()
|
||||||
|
{
|
||||||
|
return d_pixmapData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Attributes how to paint a QImage
|
||||||
|
QwtPainterCommand::ImageData* QwtPainterCommand::imageData()
|
||||||
|
{
|
||||||
|
return d_imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \return Attributes of a state change
|
||||||
|
QwtPainterCommand::StateData* QwtPainterCommand::stateData()
|
||||||
|
{
|
||||||
|
return d_stateData;
|
||||||
|
}
|
||||||
@ -0,0 +1,542 @@
|
|||||||
|
/* -*- 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 "qwt_panner.h"
|
||||||
|
#include "qwt_picker.h"
|
||||||
|
#include "qwt_painter.h"
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpixmap.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qcursor.h>
|
||||||
|
#include <qbitmap.h>
|
||||||
|
|
||||||
|
static QVector<QwtPicker *> qwtActivePickers( QWidget *w )
|
||||||
|
{
|
||||||
|
QVector<QwtPicker *> pickers;
|
||||||
|
|
||||||
|
QObjectList children = w->children();
|
||||||
|
for ( int i = 0; i < children.size(); i++ )
|
||||||
|
{
|
||||||
|
QwtPicker *picker = qobject_cast<QwtPicker *>( children[i] );
|
||||||
|
if ( picker && picker->isEnabled() )
|
||||||
|
pickers += picker;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pickers;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QwtPanner::PrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrivateData():
|
||||||
|
button( Qt::LeftButton ),
|
||||||
|
buttonModifiers( Qt::NoModifier ),
|
||||||
|
abortKey( Qt::Key_Escape ),
|
||||||
|
abortKeyModifiers( Qt::NoModifier ),
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
cursor( NULL ),
|
||||||
|
restoreCursor( NULL ),
|
||||||
|
hasCursor( false ),
|
||||||
|
#endif
|
||||||
|
isEnabled( false )
|
||||||
|
{
|
||||||
|
orientations = Qt::Vertical | Qt::Horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
~PrivateData()
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
delete cursor;
|
||||||
|
delete restoreCursor;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::MouseButton button;
|
||||||
|
Qt::KeyboardModifiers buttonModifiers;
|
||||||
|
|
||||||
|
int abortKey;
|
||||||
|
Qt::KeyboardModifiers abortKeyModifiers;
|
||||||
|
|
||||||
|
QPoint initialPos;
|
||||||
|
QPoint pos;
|
||||||
|
|
||||||
|
QPixmap pixmap;
|
||||||
|
QBitmap contentsMask;
|
||||||
|
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
QCursor *cursor;
|
||||||
|
QCursor *restoreCursor;
|
||||||
|
bool hasCursor;
|
||||||
|
#endif
|
||||||
|
bool isEnabled;
|
||||||
|
Qt::Orientations orientations;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates an panner that is enabled for the left mouse button.
|
||||||
|
|
||||||
|
\param parent Parent widget to be panned
|
||||||
|
*/
|
||||||
|
QwtPanner::QwtPanner( QWidget *parent ):
|
||||||
|
QWidget( parent )
|
||||||
|
{
|
||||||
|
d_data = new PrivateData();
|
||||||
|
|
||||||
|
setAttribute( Qt::WA_TransparentForMouseEvents );
|
||||||
|
setAttribute( Qt::WA_NoSystemBackground );
|
||||||
|
setFocusPolicy( Qt::NoFocus );
|
||||||
|
hide();
|
||||||
|
|
||||||
|
setEnabled( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
QwtPanner::~QwtPanner()
|
||||||
|
{
|
||||||
|
delete d_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the mouse button and modifiers used for panning
|
||||||
|
The defaults are Qt::LeftButton and Qt::NoModifier
|
||||||
|
*/
|
||||||
|
void QwtPanner::setMouseButton( Qt::MouseButton button,
|
||||||
|
Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->button = button;
|
||||||
|
d_data->buttonModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get mouse button and modifiers used for panning
|
||||||
|
void QwtPanner::getMouseButton( Qt::MouseButton &button,
|
||||||
|
Qt::KeyboardModifiers &modifiers ) const
|
||||||
|
{
|
||||||
|
button = d_data->button;
|
||||||
|
modifiers = d_data->buttonModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the abort key
|
||||||
|
The defaults are Qt::Key_Escape and Qt::NoModifiers
|
||||||
|
|
||||||
|
\param key Key ( See Qt::Keycode )
|
||||||
|
\param modifiers Keyboard modifiers
|
||||||
|
*/
|
||||||
|
void QwtPanner::setAbortKey( int key,
|
||||||
|
Qt::KeyboardModifiers modifiers )
|
||||||
|
{
|
||||||
|
d_data->abortKey = key;
|
||||||
|
d_data->abortKeyModifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the abort key and modifiers
|
||||||
|
void QwtPanner::getAbortKey( int &key,
|
||||||
|
Qt::KeyboardModifiers &modifiers ) const
|
||||||
|
{
|
||||||
|
key = d_data->abortKey;
|
||||||
|
modifiers = d_data->abortKeyModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Change the cursor, that is active while panning
|
||||||
|
The default is the cursor of the parent widget.
|
||||||
|
|
||||||
|
\param cursor New cursor
|
||||||
|
|
||||||
|
\sa setCursor()
|
||||||
|
*/
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
void QwtPanner::setCursor( const QCursor &cursor )
|
||||||
|
{
|
||||||
|
d_data->cursor = new QCursor( cursor );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return Cursor that is active while panning
|
||||||
|
\sa setCursor()
|
||||||
|
*/
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
const QCursor QwtPanner::cursor() const
|
||||||
|
{
|
||||||
|
if ( d_data->cursor )
|
||||||
|
return *d_data->cursor;
|
||||||
|
|
||||||
|
if ( parentWidget() )
|
||||||
|
return parentWidget()->cursor();
|
||||||
|
|
||||||
|
return QCursor();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief En/disable the panner
|
||||||
|
|
||||||
|
When enabled is true an event filter is installed for
|
||||||
|
the observed widget, otherwise the event filter is removed.
|
||||||
|
|
||||||
|
\param on true or false
|
||||||
|
\sa isEnabled(), eventFilter()
|
||||||
|
*/
|
||||||
|
void QwtPanner::setEnabled( bool on )
|
||||||
|
{
|
||||||
|
if ( d_data->isEnabled != on )
|
||||||
|
{
|
||||||
|
d_data->isEnabled = on;
|
||||||
|
|
||||||
|
QWidget *w = parentWidget();
|
||||||
|
if ( w )
|
||||||
|
{
|
||||||
|
if ( d_data->isEnabled )
|
||||||
|
{
|
||||||
|
w->installEventFilter( this );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w->removeEventFilter( this );
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the orientations, where panning is enabled
|
||||||
|
The default value is in both directions: Qt::Horizontal | Qt::Vertical
|
||||||
|
|
||||||
|
/param o Orientation
|
||||||
|
*/
|
||||||
|
void QwtPanner::setOrientations( Qt::Orientations o )
|
||||||
|
{
|
||||||
|
d_data->orientations = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return the orientation, where paning is enabled
|
||||||
|
Qt::Orientations QwtPanner::orientations() const
|
||||||
|
{
|
||||||
|
return d_data->orientations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return True if an orientation is enabled
|
||||||
|
\sa orientations(), setOrientations()
|
||||||
|
*/
|
||||||
|
bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const
|
||||||
|
{
|
||||||
|
return d_data->orientations & o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return true when enabled, false otherwise
|
||||||
|
\sa setEnabled, eventFilter()
|
||||||
|
*/
|
||||||
|
bool QwtPanner::isEnabled() const
|
||||||
|
{
|
||||||
|
return d_data->isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Paint event
|
||||||
|
|
||||||
|
Repaint the grabbed pixmap on its current position and
|
||||||
|
fill the empty spaces by the background of the parent widget.
|
||||||
|
|
||||||
|
\param event Paint event
|
||||||
|
*/
|
||||||
|
void QwtPanner::paintEvent( QPaintEvent *event )
|
||||||
|
{
|
||||||
|
int dx = d_data->pos.x() - d_data->initialPos.x();
|
||||||
|
int dy = d_data->pos.y() - d_data->initialPos.y();
|
||||||
|
|
||||||
|
QRectF r;
|
||||||
|
r.setSize( d_data->pixmap.size() );
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
r.setSize( r.size() / d_data->pixmap.devicePixelRatio() );
|
||||||
|
#endif
|
||||||
|
r.moveCenter( QPointF( r.center().x() + dx, r.center().y() + dy ) );
|
||||||
|
|
||||||
|
QPixmap pm = QwtPainter::backingStore( this, size() );
|
||||||
|
QwtPainter::fillPixmap( parentWidget(), pm );
|
||||||
|
|
||||||
|
QPainter painter( &pm );
|
||||||
|
|
||||||
|
if ( !d_data->contentsMask.isNull() )
|
||||||
|
{
|
||||||
|
QPixmap masked = d_data->pixmap;
|
||||||
|
masked.setMask( d_data->contentsMask );
|
||||||
|
painter.drawPixmap( r.toRect(), masked );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter.drawPixmap( r.toRect(), d_data->pixmap );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
if ( !d_data->contentsMask.isNull() )
|
||||||
|
pm.setMask( d_data->contentsMask );
|
||||||
|
|
||||||
|
painter.begin( this );
|
||||||
|
painter.setClipRegion( event->region() );
|
||||||
|
painter.drawPixmap( 0, 0, pm );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Calculate a mask for the contents of the panned widget
|
||||||
|
|
||||||
|
Sometimes only parts of the contents of a widget should be
|
||||||
|
panned. F.e. for a widget with a styled background with rounded borders
|
||||||
|
only the area inside of the border should be panned.
|
||||||
|
|
||||||
|
\return An empty bitmap, indicating no mask
|
||||||
|
*/
|
||||||
|
QBitmap QwtPanner::contentsMask() const
|
||||||
|
{
|
||||||
|
return QBitmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Grab the widget into a pixmap.
|
||||||
|
\return Grabbed pixmap
|
||||||
|
*/
|
||||||
|
QPixmap QwtPanner::grab() const
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
return parentWidget()->grab( parentWidget()->rect() );
|
||||||
|
#else
|
||||||
|
return QPixmap::grabWidget( parentWidget() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Event filter
|
||||||
|
|
||||||
|
When isEnabled() is true mouse events of the
|
||||||
|
observed widget are filtered.
|
||||||
|
|
||||||
|
\param object Object to be filtered
|
||||||
|
\param event Event
|
||||||
|
|
||||||
|
\return Always false, beside for paint events for the
|
||||||
|
parent widget.
|
||||||
|
|
||||||
|
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||||
|
widgetMouseMoveEvent()
|
||||||
|
*/
|
||||||
|
bool QwtPanner::eventFilter( QObject *object, QEvent *event )
|
||||||
|
{
|
||||||
|
if ( object == NULL || object != parentWidget() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch ( event->type() )
|
||||||
|
{
|
||||||
|
case QEvent::MouseButtonPress:
|
||||||
|
{
|
||||||
|
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::MouseMove:
|
||||||
|
{
|
||||||
|
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::MouseButtonRelease:
|
||||||
|
{
|
||||||
|
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::KeyPress:
|
||||||
|
{
|
||||||
|
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::KeyRelease:
|
||||||
|
{
|
||||||
|
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::Paint:
|
||||||
|
{
|
||||||
|
if ( isVisible() )
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse press event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
\sa eventFilter(), widgetMouseReleaseEvent(),
|
||||||
|
widgetMouseMoveEvent(),
|
||||||
|
*/
|
||||||
|
void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
if ( ( mouseEvent->button() != d_data->button )
|
||||||
|
|| ( mouseEvent->modifiers() != d_data->buttonModifiers ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *w = parentWidget();
|
||||||
|
if ( w == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
showCursor( true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
d_data->initialPos = d_data->pos = mouseEvent->pos();
|
||||||
|
|
||||||
|
setGeometry( parentWidget()->rect() );
|
||||||
|
|
||||||
|
// We don't want to grab the picker !
|
||||||
|
QVector<QwtPicker *> pickers = qwtActivePickers( parentWidget() );
|
||||||
|
for ( int i = 0; i < pickers.size(); i++ )
|
||||||
|
pickers[i]->setEnabled( false );
|
||||||
|
|
||||||
|
d_data->pixmap = grab();
|
||||||
|
d_data->contentsMask = contentsMask();
|
||||||
|
|
||||||
|
for ( int i = 0; i < pickers.size(); i++ )
|
||||||
|
pickers[i]->setEnabled( true );
|
||||||
|
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse move event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent()
|
||||||
|
*/
|
||||||
|
void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
if ( !isVisible() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QPoint pos = mouseEvent->pos();
|
||||||
|
if ( !isOrientationEnabled( Qt::Horizontal ) )
|
||||||
|
pos.setX( d_data->initialPos.x() );
|
||||||
|
if ( !isOrientationEnabled( Qt::Vertical ) )
|
||||||
|
pos.setY( d_data->initialPos.y() );
|
||||||
|
|
||||||
|
if ( pos != d_data->pos && rect().contains( pos ) )
|
||||||
|
{
|
||||||
|
d_data->pos = pos;
|
||||||
|
update();
|
||||||
|
|
||||||
|
Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(),
|
||||||
|
d_data->pos.y() - d_data->initialPos.y() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a mouse release event for the observed widget.
|
||||||
|
|
||||||
|
\param mouseEvent Mouse event
|
||||||
|
\sa eventFilter(), widgetMousePressEvent(),
|
||||||
|
widgetMouseMoveEvent(),
|
||||||
|
*/
|
||||||
|
void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
|
||||||
|
{
|
||||||
|
if ( isVisible() )
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
showCursor( false );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QPoint pos = mouseEvent->pos();
|
||||||
|
if ( !isOrientationEnabled( Qt::Horizontal ) )
|
||||||
|
pos.setX( d_data->initialPos.x() );
|
||||||
|
if ( !isOrientationEnabled( Qt::Vertical ) )
|
||||||
|
pos.setY( d_data->initialPos.y() );
|
||||||
|
|
||||||
|
d_data->pixmap = QPixmap();
|
||||||
|
d_data->contentsMask = QBitmap();
|
||||||
|
d_data->pos = pos;
|
||||||
|
|
||||||
|
if ( d_data->pos != d_data->initialPos )
|
||||||
|
{
|
||||||
|
Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(),
|
||||||
|
d_data->pos.y() - d_data->initialPos.y() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a key press event for the observed widget.
|
||||||
|
|
||||||
|
\param keyEvent Key event
|
||||||
|
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||||
|
*/
|
||||||
|
void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent )
|
||||||
|
{
|
||||||
|
if ( ( keyEvent->key() == d_data->abortKey )
|
||||||
|
&& ( keyEvent->modifiers() == d_data->abortKeyModifiers ) )
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
showCursor( false );
|
||||||
|
#endif
|
||||||
|
d_data->pixmap = QPixmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Handle a key release event for the observed widget.
|
||||||
|
|
||||||
|
\param keyEvent Key event
|
||||||
|
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||||
|
*/
|
||||||
|
void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
|
||||||
|
{
|
||||||
|
Q_UNUSED( keyEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_CURSOR
|
||||||
|
void QwtPanner::showCursor( bool on )
|
||||||
|
{
|
||||||
|
if ( on == d_data->hasCursor )
|
||||||
|
return;
|
||||||
|
|
||||||
|
QWidget *w = parentWidget();
|
||||||
|
if ( w == NULL || d_data->cursor == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data->hasCursor = on;
|
||||||
|
|
||||||
|
if ( on )
|
||||||
|
{
|
||||||
|
if ( w->testAttribute( Qt::WA_SetCursor ) )
|
||||||
|
{
|
||||||
|
delete d_data->restoreCursor;
|
||||||
|
d_data->restoreCursor = new QCursor( w->cursor() );
|
||||||
|
}
|
||||||
|
w->setCursor( *d_data->cursor );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( d_data->restoreCursor )
|
||||||
|
{
|
||||||
|
w->setCursor( *d_data->restoreCursor );
|
||||||
|
delete d_data->restoreCursor;
|
||||||
|
d_data->restoreCursor = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
w->unsetCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||