summaryrefslogtreecommitdiff
path: root/src/libpcp_qwt
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp_qwt')
-rw-r--r--src/libpcp_qwt/GNUmakefile27
-rw-r--r--src/libpcp_qwt/src/GNUmakefile24
-rw-r--r--src/libpcp_qwt/src/libpcp_qwt.pro173
-rw-r--r--src/libpcp_qwt/src/qwt.h22
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_scale.cpp310
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_scale.h70
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_scale_draw.cpp412
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_scale_draw.h139
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_slider.cpp597
-rw-r--r--src/libpcp_qwt/src/qwt_abstract_slider.h188
-rw-r--r--src/libpcp_qwt/src/qwt_analog_clock.cpp228
-rw-r--r--src/libpcp_qwt/src/qwt_analog_clock.h96
-rw-r--r--src/libpcp_qwt/src/qwt_arrow_button.cpp332
-rw-r--r--src/libpcp_qwt/src/qwt_arrow_button.h52
-rw-r--r--src/libpcp_qwt/src/qwt_clipper.cpp486
-rw-r--r--src/libpcp_qwt/src/qwt_clipper.h37
-rw-r--r--src/libpcp_qwt/src/qwt_color_map.cpp440
-rw-r--r--src/libpcp_qwt/src/qwt_color_map.h198
-rw-r--r--src/libpcp_qwt/src/qwt_column_symbol.cpp293
-rw-r--r--src/libpcp_qwt/src/qwt_column_symbol.h161
-rw-r--r--src/libpcp_qwt/src/qwt_compass.cpp292
-rw-r--r--src/libpcp_qwt/src/qwt_compass.h65
-rw-r--r--src/libpcp_qwt/src/qwt_compass_rose.cpp265
-rw-r--r--src/libpcp_qwt/src/qwt_compass_rose.h89
-rw-r--r--src/libpcp_qwt/src/qwt_compat.h42
-rw-r--r--src/libpcp_qwt/src/qwt_counter.cpp603
-rw-r--r--src/libpcp_qwt/src/qwt_counter.h148
-rw-r--r--src/libpcp_qwt/src/qwt_curve_fitter.cpp405
-rw-r--r--src/libpcp_qwt/src/qwt_curve_fitter.h128
-rw-r--r--src/libpcp_qwt/src/qwt_dial.cpp1156
-rw-r--r--src/libpcp_qwt/src/qwt_dial.h215
-rw-r--r--src/libpcp_qwt/src/qwt_dial_needle.cpp441
-rw-r--r--src/libpcp_qwt/src/qwt_dial_needle.h190
-rw-r--r--src/libpcp_qwt/src/qwt_double_range.cpp410
-rw-r--r--src/libpcp_qwt/src/qwt_double_range.h78
-rw-r--r--src/libpcp_qwt/src/qwt_dyngrid_layout.cpp575
-rw-r--r--src/libpcp_qwt/src/qwt_dyngrid_layout.h83
-rw-r--r--src/libpcp_qwt/src/qwt_event_pattern.cpp274
-rw-r--r--src/libpcp_qwt/src/qwt_event_pattern.h225
-rw-r--r--src/libpcp_qwt/src/qwt_global.h41
-rw-r--r--src/libpcp_qwt/src/qwt_interval.cpp334
-rw-r--r--src/libpcp_qwt/src/qwt_interval.h296
-rw-r--r--src/libpcp_qwt/src/qwt_interval_symbol.cpp300
-rw-r--r--src/libpcp_qwt/src/qwt_interval_symbol.h86
-rw-r--r--src/libpcp_qwt/src/qwt_knob.cpp665
-rw-r--r--src/libpcp_qwt/src/qwt_knob.h159
-rw-r--r--src/libpcp_qwt/src/qwt_legend.cpp519
-rw-r--r--src/libpcp_qwt/src/qwt_legend.h95
-rw-r--r--src/libpcp_qwt/src/qwt_legend_item.cpp407
-rw-r--r--src/libpcp_qwt/src/qwt_legend_item.h78
-rw-r--r--src/libpcp_qwt/src/qwt_legend_itemmanager.h66
-rw-r--r--src/libpcp_qwt/src/qwt_magnifier.cpp467
-rw-r--r--src/libpcp_qwt/src/qwt_magnifier.h86
-rw-r--r--src/libpcp_qwt/src/qwt_math.cpp45
-rw-r--r--src/libpcp_qwt/src/qwt_math.h182
-rw-r--r--src/libpcp_qwt/src/qwt_matrix_raster_data.cpp270
-rw-r--r--src/libpcp_qwt/src/qwt_matrix_raster_data.h71
-rw-r--r--src/libpcp_qwt/src/qwt_null_paintdevice.cpp428
-rw-r--r--src/libpcp_qwt/src/qwt_null_paintdevice.h89
-rw-r--r--src/libpcp_qwt/src/qwt_painter.cpp765
-rw-r--r--src/libpcp_qwt/src/qwt_painter.h154
-rw-r--r--src/libpcp_qwt/src/qwt_panner.cpp537
-rw-r--r--src/libpcp_qwt/src/qwt_panner.h100
-rw-r--r--src/libpcp_qwt/src/qwt_picker.cpp1462
-rw-r--r--src/libpcp_qwt/src/qwt_picker.h327
-rw-r--r--src/libpcp_qwt/src/qwt_picker_machine.cpp455
-rw-r--r--src/libpcp_qwt/src/qwt_picker_machine.h190
-rw-r--r--src/libpcp_qwt/src/qwt_plot.cpp751
-rw-r--r--src/libpcp_qwt/src/qwt_plot.h290
-rw-r--r--src/libpcp_qwt/src/qwt_plot_axis.cpp670
-rw-r--r--src/libpcp_qwt/src/qwt_plot_canvas.cpp1095
-rw-r--r--src/libpcp_qwt/src/qwt_plot_canvas.h171
-rw-r--r--src/libpcp_qwt/src/qwt_plot_curve.cpp1127
-rw-r--r--src/libpcp_qwt/src/qwt_plot_curve.h319
-rw-r--r--src/libpcp_qwt/src/qwt_plot_dict.cpp188
-rw-r--r--src/libpcp_qwt/src/qwt_plot_dict.h58
-rw-r--r--src/libpcp_qwt/src/qwt_plot_directpainter.cpp313
-rw-r--r--src/libpcp_qwt/src/qwt_plot_directpainter.h100
-rw-r--r--src/libpcp_qwt/src/qwt_plot_grid.cpp367
-rw-r--r--src/libpcp_qwt/src/qwt_plot_grid.h84
-rw-r--r--src/libpcp_qwt/src/qwt_plot_histogram.cpp651
-rw-r--r--src/libpcp_qwt/src/qwt_plot_histogram.h134
-rw-r--r--src/libpcp_qwt/src/qwt_plot_intervalcurve.cpp548
-rw-r--r--src/libpcp_qwt/src/qwt_plot_intervalcurve.h130
-rw-r--r--src/libpcp_qwt/src/qwt_plot_item.cpp542
-rw-r--r--src/libpcp_qwt/src/qwt_plot_item.h214
-rw-r--r--src/libpcp_qwt/src/qwt_plot_layout.cpp1267
-rw-r--r--src/libpcp_qwt/src/qwt_plot_layout.h108
-rw-r--r--src/libpcp_qwt/src/qwt_plot_magnifier.cpp143
-rw-r--r--src/libpcp_qwt/src/qwt_plot_magnifier.h55
-rw-r--r--src/libpcp_qwt/src/qwt_plot_marker.cpp608
-rw-r--r--src/libpcp_qwt/src/qwt_plot_marker.h124
-rw-r--r--src/libpcp_qwt/src/qwt_plot_panner.cpp175
-rw-r--r--src/libpcp_qwt/src/qwt_plot_panner.h60
-rw-r--r--src/libpcp_qwt/src/qwt_plot_picker.cpp383
-rw-r--r--src/libpcp_qwt/src/qwt_plot_picker.h115
-rw-r--r--src/libpcp_qwt/src/qwt_plot_rasteritem.cpp904
-rw-r--r--src/libpcp_qwt/src/qwt_plot_rasteritem.h146
-rw-r--r--src/libpcp_qwt/src/qwt_plot_renderer.cpp897
-rw-r--r--src/libpcp_qwt/src/qwt_plot_renderer.h154
-rw-r--r--src/libpcp_qwt/src/qwt_plot_rescaler.cpp628
-rw-r--r--src/libpcp_qwt/src/qwt_plot_rescaler.h143
-rw-r--r--src/libpcp_qwt/src/qwt_plot_scaleitem.cpp445
-rw-r--r--src/libpcp_qwt/src/qwt_plot_scaleitem.h94
-rw-r--r--src/libpcp_qwt/src/qwt_plot_seriesitem.cpp90
-rw-r--r--src/libpcp_qwt/src/qwt_plot_seriesitem.h206
-rw-r--r--src/libpcp_qwt/src/qwt_plot_spectrocurve.cpp300
-rw-r--r--src/libpcp_qwt/src/qwt_plot_spectrocurve.h76
-rw-r--r--src/libpcp_qwt/src/qwt_plot_spectrogram.cpp663
-rw-r--r--src/libpcp_qwt/src/qwt_plot_spectrogram.h115
-rw-r--r--src/libpcp_qwt/src/qwt_plot_svgitem.cpp214
-rw-r--r--src/libpcp_qwt/src/qwt_plot_svgitem.h61
-rw-r--r--src/libpcp_qwt/src/qwt_plot_xml.cpp41
-rw-r--r--src/libpcp_qwt/src/qwt_plot_zoomer.cpp607
-rw-r--r--src/libpcp_qwt/src/qwt_plot_zoomer.h104
-rw-r--r--src/libpcp_qwt/src/qwt_point_3d.cpp22
-rw-r--r--src/libpcp_qwt/src/qwt_point_3d.h189
-rw-r--r--src/libpcp_qwt/src/qwt_point_polar.cpp114
-rw-r--r--src/libpcp_qwt/src/qwt_point_polar.h195
-rw-r--r--src/libpcp_qwt/src/qwt_raster_data.cpp390
-rw-r--r--src/libpcp_qwt/src/qwt_raster_data.h95
-rw-r--r--src/libpcp_qwt/src/qwt_round_scale_draw.cpp309
-rw-r--r--src/libpcp_qwt/src/qwt_round_scale_draw.h68
-rw-r--r--src/libpcp_qwt/src/qwt_sampling_thread.cpp106
-rw-r--r--src/libpcp_qwt/src/qwt_sampling_thread.h50
-rw-r--r--src/libpcp_qwt/src/qwt_scale_div.cpp173
-rw-r--r--src/libpcp_qwt/src/qwt_scale_div.h132
-rw-r--r--src/libpcp_qwt/src/qwt_scale_draw.cpp903
-rw-r--r--src/libpcp_qwt/src/qwt_scale_draw.h117
-rw-r--r--src/libpcp_qwt/src/qwt_scale_engine.cpp967
-rw-r--r--src/libpcp_qwt/src/qwt_scale_engine.h217
-rw-r--r--src/libpcp_qwt/src/qwt_scale_map.cpp344
-rw-r--r--src/libpcp_qwt/src/qwt_scale_map.h219
-rw-r--r--src/libpcp_qwt/src/qwt_scale_widget.cpp918
-rw-r--r--src/libpcp_qwt/src/qwt_scale_widget.h135
-rw-r--r--src/libpcp_qwt/src/qwt_series_data.cpp591
-rw-r--r--src/libpcp_qwt/src/qwt_series_data.h460
-rw-r--r--src/libpcp_qwt/src/qwt_slider.cpp805
-rw-r--r--src/libpcp_qwt/src/qwt_slider.h150
-rw-r--r--src/libpcp_qwt/src/qwt_spline.cpp380
-rw-r--r--src/libpcp_qwt/src/qwt_spline.h101
-rw-r--r--src/libpcp_qwt/src/qwt_symbol.cpp1006
-rw-r--r--src/libpcp_qwt/src/qwt_symbol.h154
-rw-r--r--src/libpcp_qwt/src/qwt_system_clock.cpp364
-rw-r--r--src/libpcp_qwt/src/qwt_system_clock.h49
-rw-r--r--src/libpcp_qwt/src/qwt_text.cpp643
-rw-r--r--src/libpcp_qwt/src/qwt_text.h216
-rw-r--r--src/libpcp_qwt/src/qwt_text_engine.cpp344
-rw-r--r--src/libpcp_qwt/src/qwt_text_engine.h172
-rw-r--r--src/libpcp_qwt/src/qwt_text_label.cpp306
-rw-r--r--src/libpcp_qwt/src/qwt_text_label.h72
-rw-r--r--src/libpcp_qwt/src/qwt_thermo.cpp1036
-rw-r--r--src/libpcp_qwt/src/qwt_thermo.h202
-rw-r--r--src/libpcp_qwt/src/qwt_wheel.cpp544
-rw-r--r--src/libpcp_qwt/src/qwt_wheel.h89
155 files changed, 48668 insertions, 0 deletions
diff --git a/src/libpcp_qwt/GNUmakefile b/src/libpcp_qwt/GNUmakefile
new file mode 100644
index 0000000..552118e
--- /dev/null
+++ b/src/libpcp_qwt/GNUmakefile
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+# License for more details.
+#
+
+TOPDIR = ../..
+include $(TOPDIR)/src/include/builddefs
+
+SUBDIRS = src
+
+default install : $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+
+include $(BUILDRULES)
+
+default_pcp : default
+
+install_pcp : install
diff --git a/src/libpcp_qwt/src/GNUmakefile b/src/libpcp_qwt/src/GNUmakefile
new file mode 100644
index 0000000..d1c2139
--- /dev/null
+++ b/src/libpcp_qwt/src/GNUmakefile
@@ -0,0 +1,24 @@
+TOPDIR = ../../..
+LIBRARY = libpcp_qwt
+PROJECT = $(LIBRARY).pro
+include $(TOPDIR)/src/include/builddefs
+
+HEADERS = $(shell echo *.h)
+SOURCES = $(shell echo *.cpp)
+
+default: build-me
+
+ifeq "$(ENABLE_QT)" "true"
+build-me: $(PROJECT)
+ $(QTMAKE)
+else
+build-me:
+endif
+
+include $(BUILDRULES)
+
+install: default
+
+default_pcp: default
+
+install_pcp: install
diff --git a/src/libpcp_qwt/src/libpcp_qwt.pro b/src/libpcp_qwt/src/libpcp_qwt.pro
new file mode 100644
index 0000000..9b64ab5
--- /dev/null
+++ b/src/libpcp_qwt/src/libpcp_qwt.pro
@@ -0,0 +1,173 @@
+TARGET = pcp_qwt
+TEMPLATE = lib
+VERSION = 6.0.2
+CONFIG += qt staticlib warn_on
+QT = core gui network svg
+
+HEADERS += \
+ qwt.h \
+ qwt_abstract_scale_draw.h \
+ qwt_interval_symbol.h \
+ qwt_clipper.h \
+ qwt_color_map.h \
+ qwt_compat.h \
+ qwt_column_symbol.h \
+ qwt_interval.h \
+ qwt_dyngrid_layout.h \
+ qwt_global.h \
+ qwt_math.h \
+ qwt_magnifier.h \
+ qwt_null_paintdevice.h \
+ qwt_painter.h \
+ qwt_panner.h \
+ qwt_picker.h \
+ qwt_picker_machine.h \
+ qwt_point_3d.h \
+ qwt_point_polar.h \
+ qwt_round_scale_draw.h \
+ qwt_scale_div.h \
+ qwt_scale_draw.h \
+ qwt_scale_engine.h \
+ qwt_scale_map.h \
+ qwt_spline.h \
+ qwt_symbol.h \
+ qwt_system_clock.h \
+ qwt_text_engine.h \
+ qwt_text_label.h \
+ qwt_text.h
+
+SOURCES += \
+ qwt_abstract_scale_draw.cpp \
+ qwt_interval_symbol.cpp \
+ qwt_clipper.cpp \
+ qwt_color_map.cpp \
+ qwt_column_symbol.cpp \
+ qwt_interval.cpp \
+ qwt_dyngrid_layout.cpp \
+ qwt_math.cpp \
+ qwt_magnifier.cpp \
+ qwt_panner.cpp \
+ qwt_null_paintdevice.cpp \
+ qwt_painter.cpp \
+ qwt_picker.cpp \
+ qwt_round_scale_draw.cpp \
+ qwt_scale_div.cpp \
+ qwt_scale_draw.cpp \
+ qwt_scale_map.cpp \
+ qwt_spline.cpp \
+ qwt_text_engine.cpp \
+ qwt_text_label.cpp \
+ qwt_text.cpp \
+ qwt_event_pattern.cpp \
+ qwt_picker_machine.cpp \
+ qwt_point_3d.cpp \
+ qwt_point_polar.cpp \
+ qwt_scale_engine.cpp \
+ qwt_symbol.cpp \
+ qwt_system_clock.cpp
+
+# qwt plot
+HEADERS += \
+ qwt_curve_fitter.h \
+ qwt_event_pattern.h \
+ qwt_legend.h \
+ qwt_legend_item.h \
+ qwt_legend_itemmanager.h \
+ qwt_plot.h \
+ qwt_plot_renderer.h \
+ qwt_plot_curve.h \
+ qwt_plot_dict.h \
+ qwt_plot_directpainter.h \
+ qwt_plot_grid.h \
+ qwt_plot_histogram.h \
+ qwt_plot_item.h \
+ qwt_plot_intervalcurve.h \
+ qwt_plot_layout.h \
+ qwt_plot_marker.h \
+ qwt_plot_rasteritem.h \
+ qwt_plot_spectrogram.h \
+ qwt_plot_spectrocurve.h \
+ qwt_plot_scaleitem.h \
+ qwt_plot_seriesitem.h \
+ qwt_plot_canvas.h \
+ qwt_plot_panner.h \
+ qwt_plot_picker.h \
+ qwt_plot_zoomer.h \
+ qwt_plot_magnifier.h \
+ qwt_plot_rescaler.h \
+ qwt_raster_data.h \
+ qwt_matrix_raster_data.h \
+ qwt_sampling_thread.h \
+ qwt_series_data.h \
+ qwt_scale_widget.h
+
+SOURCES += \
+ qwt_curve_fitter.cpp \
+ qwt_legend.cpp \
+ qwt_legend_item.cpp \
+ qwt_plot.cpp \
+ qwt_plot_renderer.cpp \
+ qwt_plot_xml.cpp \
+ qwt_plot_axis.cpp \
+ qwt_plot_curve.cpp \
+ qwt_plot_dict.cpp \
+ qwt_plot_directpainter.cpp \
+ qwt_plot_grid.cpp \
+ qwt_plot_histogram.cpp \
+ qwt_plot_item.cpp \
+ qwt_plot_intervalcurve.cpp \
+ qwt_plot_spectrogram.cpp \
+ qwt_plot_spectrocurve.cpp \
+ qwt_plot_scaleitem.cpp \
+ qwt_plot_seriesitem.cpp \
+ qwt_plot_marker.cpp \
+ qwt_plot_layout.cpp \
+ qwt_plot_canvas.cpp \
+ qwt_plot_panner.cpp \
+ qwt_plot_rasteritem.cpp \
+ qwt_plot_picker.cpp \
+ qwt_plot_zoomer.cpp \
+ qwt_plot_magnifier.cpp \
+ qwt_plot_rescaler.cpp \
+ qwt_raster_data.cpp \
+ qwt_matrix_raster_data.cpp \
+ qwt_sampling_thread.cpp \
+ qwt_series_data.cpp \
+ qwt_scale_widget.cpp
+
+# svg
+HEADERS += qwt_plot_svgitem.h
+SOURCES += qwt_plot_svgitem.cpp
+
+# widgets
+HEADERS += \
+ qwt_abstract_slider.h \
+ qwt_abstract_scale.h \
+ qwt_arrow_button.h \
+ qwt_analog_clock.h \
+ qwt_compass.h \
+ qwt_compass_rose.h \
+ qwt_counter.h \
+ qwt_dial.h \
+ qwt_dial_needle.h \
+ qwt_double_range.h \
+ qwt_knob.h \
+ qwt_slider.h \
+ qwt_thermo.h \
+ qwt_wheel.h
+
+SOURCES += \
+ qwt_abstract_slider.cpp \
+ qwt_abstract_scale.cpp \
+ qwt_arrow_button.cpp \
+ qwt_analog_clock.cpp \
+ qwt_compass.cpp \
+ qwt_compass_rose.cpp \
+ qwt_counter.cpp \
+ qwt_dial.cpp \
+ qwt_dial_needle.cpp \
+ qwt_double_range.cpp \
+ qwt_knob.cpp \
+ qwt_slider.cpp \
+ qwt_thermo.cpp \
+ qwt_wheel.cpp
diff --git a/src/libpcp_qwt/src/qwt.h b/src/libpcp_qwt/src/qwt.h
new file mode 100644
index 0000000..3749493
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt.h
@@ -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
diff --git a/src/libpcp_qwt/src/qwt_abstract_scale.cpp b/src/libpcp_qwt/src/qwt_abstract_scale.cpp
new file mode 100644
index 0000000..e44776e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_scale.cpp
@@ -0,0 +1,310 @@
+/* -*- 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 ),
+ autoScale( true )
+ {
+ scaleEngine = new QwtLinearScaleEngine;
+ scaleDraw = new QwtScaleDraw();
+ }
+
+ ~PrivateData()
+ {
+ delete scaleEngine;
+ delete scaleDraw;
+ }
+
+ QwtScaleEngine *scaleEngine;
+ QwtAbstractScaleDraw *scaleDraw;
+
+ int maxMajor;
+ int maxMinor;
+ double stepSize;
+
+ bool autoScale;
+};
+
+/*!
+ Constructor
+
+ Creates a default QwtScaleDraw and a QwtLinearScaleEngine.
+ Autoscaling is enabled, and the stepSize is initialized by 0.0.
+*/
+
+QwtAbstractScale::QwtAbstractScale()
+{
+ d_data = new PrivateData;
+ rescale( 0.0, 100.0 );
+}
+
+//! Destructor
+QwtAbstractScale::~QwtAbstractScale()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Specify a scale.
+
+ Disable autoscaling and define a scale by an interval and a step size
+
+ \param vmin lower limit of the scale interval
+ \param vmax upper limit of the scale interval
+ \param stepSize major step size
+ \sa setAutoScale()
+*/
+void QwtAbstractScale::setScale( double vmin, double vmax, double stepSize )
+{
+ d_data->autoScale = false;
+ d_data->stepSize = stepSize;
+
+ rescale( vmin, vmax, stepSize );
+}
+
+/*!
+ \brief Specify a scale.
+
+ Disable autoscaling and define a scale by an interval and a step size
+
+ \param interval Interval
+ \param stepSize major step size
+ \sa setAutoScale()
+*/
+void QwtAbstractScale::setScale( const QwtInterval &interval, double stepSize )
+{
+ setScale( interval.minValue(), interval.maxValue(), stepSize );
+}
+
+
+/*!
+ \brief Specify a scale.
+
+ Disable autoscaling and define a scale by a scale division
+
+ \param scaleDiv Scale division
+ \sa setAutoScale()
+*/
+void QwtAbstractScale::setScale( const QwtScaleDiv &scaleDiv )
+{
+ d_data->autoScale = false;
+
+ if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
+ {
+ d_data->scaleDraw->setScaleDiv( scaleDiv );
+ scaleChange();
+ }
+}
+
+/*!
+ Recalculate the scale division and update the scale draw.
+
+ \param vmin Lower limit of the scale interval
+ \param vmax Upper limit of the scale interval
+ \param stepSize Major step size
+
+ \sa scaleChange()
+*/
+void QwtAbstractScale::rescale( double vmin, double vmax, double stepSize )
+{
+ const QwtScaleDiv scaleDiv = d_data->scaleEngine->divideScale(
+ vmin, vmax, d_data->maxMajor, d_data->maxMinor, stepSize );
+
+ if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
+ {
+ d_data->scaleDraw->setTransformation(
+ d_data->scaleEngine->transformation() );
+ d_data->scaleDraw->setScaleDiv( scaleDiv );
+ scaleChange();
+ }
+}
+
+/*!
+ \brief Advise the widget to control the scale range internally.
+
+ Autoscaling is on by default.
+ \sa setScale(), autoScale()
+*/
+void QwtAbstractScale::setAutoScale()
+{
+ if ( !d_data->autoScale )
+ {
+ d_data->autoScale = true;
+ scaleChange();
+ }
+}
+
+/*!
+ \return \c true if autoscaling is enabled
+*/
+bool QwtAbstractScale::autoScale() const
+{
+ return d_data->autoScale;
+}
+
+/*!
+ \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 QwtAbstractScaleDraw
+*/
+void QwtAbstractScale::setScaleMaxMajor( int ticks )
+{
+ if ( ticks != d_data->maxMajor )
+ {
+ d_data->maxMajor = ticks;
+ updateScaleDraw();
+ }
+}
+
+/*!
+ \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
+ \sa QwtAbstractScaleDraw
+*/
+void QwtAbstractScale::setScaleMaxMinor( int ticks )
+{
+ if ( ticks != d_data->maxMinor )
+ {
+ d_data->maxMinor = ticks;
+ updateScaleDraw();
+ }
+}
+
+/*!
+ \return Max. number of minor tick intervals
+ The default value is 3.
+*/
+int QwtAbstractScale::scaleMaxMinor() const
+{
+ return d_data->maxMinor;
+}
+
+/*!
+ \return Max. number of major tick intervals
+ The default value is 5.
+*/
+int QwtAbstractScale::scaleMaxMajor() const
+{
+ return d_data->maxMajor;
+}
+
+/*!
+ \brief Set a scale draw
+
+ scaleDraw has to be created with new and will be deleted in
+ ~QwtAbstractScale or the next call of setAbstractScaleDraw.
+*/
+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;
+}
+
+void QwtAbstractScale::updateScaleDraw()
+{
+ rescale( d_data->scaleDraw->scaleDiv().lowerBound(),
+ d_data->scaleDraw->scaleDiv().upperBound(), d_data->stepSize );
+}
+
+/*!
+ \brief Set a scale engine
+
+ The scale engine is responsible for calculating the scale division,
+ and in case of auto scaling how to align the scale.
+
+ scaleEngine has to be created with new and will be deleted in
+ ~QwtAbstractScale 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;
+}
+
+/*!
+ \brief Notify changed scale
+
+ Dummy empty implementation, intended to be overloaded by derived classes
+*/
+void QwtAbstractScale::scaleChange()
+{
+}
+
+/*!
+ \return abstractScaleDraw()->scaleMap()
+*/
+const QwtScaleMap &QwtAbstractScale::scaleMap() const
+{
+ return d_data->scaleDraw->scaleMap();
+}
diff --git a/src/libpcp_qwt/src/qwt_abstract_scale.h b/src/libpcp_qwt/src/qwt_abstract_scale.h
new file mode 100644
index 0000000..670d228
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_scale.h
@@ -0,0 +1,70 @@
+/* -*- 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"
+
+class QwtScaleEngine;
+class QwtAbstractScaleDraw;
+class QwtScaleDiv;
+class QwtScaleMap;
+class QwtInterval;
+
+/*!
+ \brief An abstract base class for classes containing a scale
+
+ QwtAbstractScale is used to provide classes with a QwtScaleDraw,
+ and a QwtScaleDiv. The QwtScaleDiv might be set explicitely
+ or calculated by a QwtScaleEngine.
+*/
+
+class QWT_EXPORT QwtAbstractScale
+{
+public:
+ QwtAbstractScale();
+ virtual ~QwtAbstractScale();
+
+ void setScale( double vmin, double vmax, double step = 0.0 );
+ void setScale( const QwtInterval &, double step = 0.0 );
+ void setScale( const QwtScaleDiv & );
+
+ void setAutoScale();
+ bool autoScale() const;
+
+ void setScaleMaxMajor( int ticks );
+ int scaleMaxMinor() const;
+
+ void setScaleMaxMinor( int ticks );
+ int scaleMaxMajor() const;
+
+ void setScaleEngine( QwtScaleEngine * );
+ const QwtScaleEngine *scaleEngine() const;
+ QwtScaleEngine *scaleEngine();
+
+ const QwtScaleMap &scaleMap() const;
+
+protected:
+ void rescale( double vmin, double vmax, double step = 0.0 );
+
+ void setAbstractScaleDraw( QwtAbstractScaleDraw * );
+ const QwtAbstractScaleDraw *abstractScaleDraw() const;
+ QwtAbstractScaleDraw *abstractScaleDraw();
+
+ virtual void scaleChange();
+
+private:
+ void updateScaleDraw();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_abstract_scale_draw.cpp b/src/libpcp_qwt/src/qwt_abstract_scale_draw.cpp
new file mode 100644
index 0000000..49230b7
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_scale_draw.cpp
@@ -0,0 +1,412 @@
+/* -*- 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 scldiv;
+
+ 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
+ \sa enableComponent()
+*/
+bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const
+{
+ return ( d_data->components & component );
+}
+
+/*!
+ Change the scale division
+ \param sd New scale division
+*/
+void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &sd )
+{
+ d_data->scldiv = sd;
+ d_data->map.setScaleInterval( sd.lowerBound(), sd.upperBound() );
+ d_data->labelCache.clear();
+}
+
+/*!
+ Change the transformation of the scale
+ \param transformation New scale transformation
+*/
+void QwtAbstractScaleDraw::setTransformation(
+ QwtScaleTransformation *transformation )
+{
+ d_data->map.setTransformation( transformation );
+}
+
+//! \return Map how to translate between scale and pixel values
+const QwtScaleMap &QwtAbstractScaleDraw::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->scldiv;
+}
+
+/*!
+ \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->scldiv.ticks( QwtScaleDiv::MajorTick );
+
+ for ( int i = 0; i < majorTicks.count(); i++ )
+ {
+ const double v = majorTicks[i];
+ if ( d_data->scldiv.contains( v ) )
+ drawLabel( painter, v );
+ }
+
+ painter->restore();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ {
+ painter->save();
+
+ QPen 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 QList<double> &ticks = d_data->scldiv.ticks( tickType );
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ const double v = ticks[i];
+ if ( d_data->scldiv.contains( v ) )
+ drawTick( painter, v, d_data->tickLength[tickType] );
+ }
+ }
+
+ painter->restore();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
+ {
+ painter->save();
+
+ QPen 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.
+
+ \sa setSpacing()
+*/
+double QwtAbstractScaleDraw::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ \brief Set a minimum for the extent
+
+ The extent is calculated from the coomponents of the
+ scale draw. In situations, where the labels are
+ changing and the layout depends on the extent (f.e scrolling
+ a scale), setting an upper limit as minimum extent will
+ avoid jumps of the layout.
+
+ \param minExtent Minimum extent
+
+ \sa extent(), minimumExtent()
+*/
+void QwtAbstractScaleDraw::setMinimumExtent( double minExtent )
+{
+ if ( minExtent < 0.0 )
+ minExtent = 0.0;
+
+ d_data->minExtent = minExtent;
+}
+
+/*!
+ Get the 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 the 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::system().toString(value).
+ This method is often overloaded by applications to have individual
+ labels.
+
+ \param value Value
+ \return Label string.
+*/
+QwtText QwtAbstractScaleDraw::label( double value ) const
+{
+ return QLocale().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 it = d_data->labelCache.find( value );
+ if ( it == d_data->labelCache.end() )
+ {
+ QwtText lbl = label( value );
+ lbl.setRenderFlags( 0 );
+ lbl.setLayoutAttribute( QwtText::MinimumLayout );
+
+ ( void )lbl.textSize( font ); // initialize the internal cache
+
+ it = d_data->labelCache.insert( value, lbl );
+ }
+
+ return ( *it );
+}
+
+/*!
+ Invalidate the cache used by QwtAbstractScaleDraw::tickLabel
+
+ The cache is invalidated, when a new QwtScaleDiv is set. If
+ the labels need to be changed. while the same QwtScaleDiv is set,
+ invalidateCache() needs to be called manually.
+*/
+void QwtAbstractScaleDraw::invalidateCache()
+{
+ d_data->labelCache.clear();
+}
diff --git a/src/libpcp_qwt/src/qwt_abstract_scale_draw.h b/src/libpcp_qwt/src/qwt_abstract_scale_draw.h
new file mode 100644
index 0000000..1dd64c0
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_scale_draw.h
@@ -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_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 QwtScaleTransformation;
+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 QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s),
+ the scale can be drawn with the QwtAbstractScaleDraw::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 &s );
+ const QwtScaleDiv& scaleDiv() const;
+
+ void setTransformation( QwtScaleTransformation * );
+ 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 margin );
+ 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 distcance from the baseline to the outermost
+ pixel of the scale draw in opposite to its orientation.
+ It is at least minimumExtent() pixels.
+
+ \sa setMinimumExtent(), minimumExtent()
+ */
+ virtual double extent( const QFont & ) const = 0;
+
+ void setMinimumExtent( double );
+ double minimumExtent() const;
+
+protected:
+ /*!
+ Draw a tick
+
+ \param painter Painter
+ \param value Value of the tick
+ \param len Lenght 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
diff --git a/src/libpcp_qwt/src/qwt_abstract_slider.cpp b/src/libpcp_qwt/src/qwt_abstract_slider.cpp
new file mode 100644
index 0000000..e2dbcff
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_slider.cpp
@@ -0,0 +1,597 @@
+/* -*- 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_math.h"
+#include <qevent.h>
+#include <qdatetime.h>
+
+#if QT_VERSION < 0x040601
+#define qFabs(x) ::fabs(x)
+#define qExp(x) ::exp(x)
+#endif
+
+class QwtAbstractSlider::PrivateData
+{
+public:
+ PrivateData():
+ scrollMode( QwtAbstractSlider::ScrNone ),
+ mouseOffset( 0.0 ),
+ tracking( true ),
+ tmrID( 0 ),
+ updTime( 150 ),
+ mass( 0.0 ),
+ readOnly( false )
+ {
+ }
+
+ QwtAbstractSlider::ScrollMode scrollMode;
+ double mouseOffset;
+ int direction;
+ int tracking;
+
+ int tmrID;
+ int updTime;
+ int timerTick;
+ QTime time;
+ double speed;
+ double mass;
+ Qt::Orientation orientation;
+ bool readOnly;
+};
+
+/*!
+ \brief Constructor
+
+ \param orientation Orientation
+ \param parent Parent widget
+*/
+QwtAbstractSlider::QwtAbstractSlider(
+ Qt::Orientation orientation, QWidget *parent ):
+ QWidget( parent, NULL )
+{
+ d_data = new QwtAbstractSlider::PrivateData;
+ d_data->orientation = orientation;
+
+ setFocusPolicy( Qt::TabFocus );
+}
+
+//! Destructor
+QwtAbstractSlider::~QwtAbstractSlider()
+{
+ if ( d_data->tmrID )
+ killTimer( d_data->tmrID );
+
+ delete d_data;
+}
+
+/*!
+ En/Disable read only mode
+
+ In read only mode the slider can't be controlled by mouse
+ or keyboard.
+
+ \param readOnly Enables in case of true
+ \sa isReadOnly()
+*/
+void QwtAbstractSlider::setReadOnly( bool readOnly )
+{
+ d_data->readOnly = readOnly;
+ 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 Set the orientation.
+ \param o Orientation. Allowed values are
+ Qt::Horizontal and Qt::Vertical.
+*/
+void QwtAbstractSlider::setOrientation( Qt::Orientation o )
+{
+ d_data->orientation = o;
+}
+
+/*!
+ \return Orientation
+ \sa setOrientation()
+*/
+Qt::Orientation QwtAbstractSlider::orientation() const
+{
+ return d_data->orientation;
+}
+
+//! Stop updating if automatic scrolling is active
+
+void QwtAbstractSlider::stopMoving()
+{
+ if ( d_data->tmrID )
+ {
+ killTimer( d_data->tmrID );
+ d_data->tmrID = 0;
+ }
+}
+
+/*!
+ \brief Specify the update interval for automatic scrolling
+ \param t update interval in milliseconds
+ \sa getScrollMode()
+*/
+void QwtAbstractSlider::setUpdateTime( int t )
+{
+ if ( t < 50 )
+ t = 50;
+ d_data->updTime = t;
+}
+
+
+/*!
+ Mouse press event handler
+ \param e Mouse event
+*/
+void QwtAbstractSlider::mousePressEvent( QMouseEvent *e )
+{
+ if ( isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+ if ( !isValid() )
+ return;
+
+ const QPoint &p = e->pos();
+
+ d_data->timerTick = 0;
+
+ getScrollMode( p, d_data->scrollMode, d_data->direction );
+ stopMoving();
+
+ switch ( d_data->scrollMode )
+ {
+ case ScrPage:
+ case ScrTimer:
+ d_data->mouseOffset = 0;
+ d_data->tmrID = startTimer( qMax( 250, 2 * d_data->updTime ) );
+ break;
+
+ case ScrMouse:
+ d_data->time.start();
+ d_data->speed = 0;
+ d_data->mouseOffset = getValue( p ) - value();
+ Q_EMIT sliderPressed();
+ break;
+
+ default:
+ d_data->mouseOffset = 0;
+ d_data->direction = 0;
+ break;
+ }
+}
+
+
+//! Emits a valueChanged() signal if necessary
+void QwtAbstractSlider::buttonReleased()
+{
+ if ( ( !d_data->tracking ) || ( value() != prevValue() ) )
+ Q_EMIT valueChanged( value() );
+}
+
+
+/*!
+ Mouse Release Event handler
+ \param e Mouse event
+*/
+void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+ if ( !isValid() )
+ return;
+
+ const double inc = step();
+
+ switch ( d_data->scrollMode )
+ {
+ case ScrMouse:
+ {
+ setPosition( e->pos() );
+ d_data->direction = 0;
+ d_data->mouseOffset = 0;
+ if ( d_data->mass > 0.0 )
+ {
+ const int ms = d_data->time.elapsed();
+ if ( ( qFabs( d_data->speed ) > 0.0 ) && ( ms < 50 ) )
+ d_data->tmrID = startTimer( d_data->updTime );
+ }
+ else
+ {
+ d_data->scrollMode = ScrNone;
+ buttonReleased();
+ }
+ Q_EMIT sliderReleased();
+
+ break;
+ }
+
+ case ScrDirect:
+ {
+ setPosition( e->pos() );
+ d_data->direction = 0;
+ d_data->mouseOffset = 0;
+ d_data->scrollMode = ScrNone;
+ buttonReleased();
+ break;
+ }
+
+ case ScrPage:
+ {
+ stopMoving();
+ if ( !d_data->timerTick )
+ QwtDoubleRange::incPages( d_data->direction );
+ d_data->timerTick = 0;
+ buttonReleased();
+ d_data->scrollMode = ScrNone;
+ break;
+ }
+
+ case ScrTimer:
+ {
+ stopMoving();
+ if ( !d_data->timerTick )
+ QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc );
+ d_data->timerTick = 0;
+ buttonReleased();
+ d_data->scrollMode = ScrNone;
+ break;
+ }
+
+ default:
+ {
+ d_data->scrollMode = ScrNone;
+ buttonReleased();
+ }
+ }
+}
+
+
+/*!
+ Move the slider to a specified point, adjust the value
+ and emit signals if necessary.
+*/
+void QwtAbstractSlider::setPosition( const QPoint &p )
+{
+ QwtDoubleRange::fitValue( getValue( p ) - d_data->mouseOffset );
+}
+
+
+/*!
+ \brief Enables or disables tracking.
+
+ If tracking is enabled, the slider emits a
+ valueChanged() signal whenever its value
+ changes (the default behaviour). If tracking
+ is disabled, the value changed() signal will only
+ be emitted if:<ul>
+ <li>the user releases the mouse
+ button and the value has changed or
+ <li>at the end of automatic scrolling.</ul>
+ Tracking is enabled by default.
+ \param enable \c true (enable) or \c false (disable) tracking.
+*/
+void QwtAbstractSlider::setTracking( bool enable )
+{
+ d_data->tracking = enable;
+}
+
+/*!
+ Mouse Move Event handler
+ \param e Mouse event
+*/
+void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+
+ if ( !isValid() )
+ return;
+
+ if ( d_data->scrollMode == ScrMouse )
+ {
+ setPosition( e->pos() );
+ if ( d_data->mass > 0.0 )
+ {
+ double ms = double( d_data->time.elapsed() );
+ if ( ms < 1.0 )
+ ms = 1.0;
+ d_data->speed = ( exactValue() - exactPrevValue() ) / ms;
+ d_data->time.start();
+ }
+ if ( value() != prevValue() )
+ Q_EMIT sliderMoved( value() );
+ }
+}
+
+/*!
+ Wheel Event handler
+ \param e Whell event
+*/
+void QwtAbstractSlider::wheelEvent( QWheelEvent *e )
+{
+ if ( isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+
+ if ( !isValid() )
+ return;
+
+ QwtAbstractSlider::ScrollMode mode = ScrNone;
+ int direction = 0;
+
+ // Give derived classes a chance to say ScrNone
+ getScrollMode( e->pos(), mode, direction );
+ if ( mode != QwtAbstractSlider::ScrNone )
+ {
+ // Most mouse types work in steps of 15 degrees, in which case
+ // the delta value is a multiple of 120
+
+ const int inc = e->delta() / 120;
+ QwtDoubleRange::incPages( inc );
+ if ( value() != prevValue() )
+ Q_EMIT sliderMoved( value() );
+ }
+}
+
+/*!
+ Handles key events
+
+ - Key_Down, KeyLeft\n
+ Decrement by 1
+ - Key_Up, Key_Right\n
+ Increment by 1
+
+ \param e Key event
+ \sa isReadOnly()
+*/
+void QwtAbstractSlider::keyPressEvent( QKeyEvent *e )
+{
+ if ( isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+
+ if ( !isValid() )
+ return;
+
+ int increment = 0;
+ switch ( e->key() )
+ {
+ case Qt::Key_Down:
+ if ( orientation() == Qt::Vertical )
+ increment = -1;
+ break;
+ case Qt::Key_Up:
+ if ( orientation() == Qt::Vertical )
+ increment = 1;
+ break;
+ case Qt::Key_Left:
+ if ( orientation() == Qt::Horizontal )
+ increment = -1;
+ break;
+ case Qt::Key_Right:
+ if ( orientation() == Qt::Horizontal )
+ increment = 1;
+ break;
+ default:;
+ e->ignore();
+ }
+
+ if ( increment != 0 )
+ {
+ QwtDoubleRange::incValue( increment );
+ if ( value() != prevValue() )
+ Q_EMIT sliderMoved( value() );
+ }
+}
+
+/*!
+ Qt timer event
+ \param e Timer event
+*/
+void QwtAbstractSlider::timerEvent( QTimerEvent * )
+{
+ const double inc = step();
+
+ switch ( d_data->scrollMode )
+ {
+ case ScrMouse:
+ {
+ if ( d_data->mass > 0.0 )
+ {
+ d_data->speed *= qExp( - double( d_data->updTime ) * 0.001 / d_data->mass );
+ const double newval =
+ exactValue() + d_data->speed * double( d_data->updTime );
+ QwtDoubleRange::fitValue( newval );
+ // stop if d_data->speed < one step per second
+ if ( qFabs( d_data->speed ) < 0.001 * qFabs( step() ) )
+ {
+ d_data->speed = 0;
+ stopMoving();
+ buttonReleased();
+ }
+
+ }
+ else
+ stopMoving();
+ break;
+ }
+
+ case ScrPage:
+ {
+ QwtDoubleRange::incPages( d_data->direction );
+ if ( !d_data->timerTick )
+ {
+ killTimer( d_data->tmrID );
+ d_data->tmrID = startTimer( d_data->updTime );
+ }
+ break;
+ }
+ case ScrTimer:
+ {
+ QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc );
+ if ( !d_data->timerTick )
+ {
+ killTimer( d_data->tmrID );
+ d_data->tmrID = startTimer( d_data->updTime );
+ }
+ break;
+ }
+ default:
+ {
+ stopMoving();
+ break;
+ }
+ }
+
+ d_data->timerTick = 1;
+}
+
+
+/*!
+ Notify change of value
+
+ This function can be reimplemented by derived classes
+ in order to keep track of changes, i.e. repaint the widget.
+ The default implementation emits a valueChanged() signal
+ if tracking is enabled.
+*/
+void QwtAbstractSlider::valueChange()
+{
+ if ( d_data->tracking )
+ Q_EMIT valueChanged( value() );
+}
+
+/*!
+ \brief Set the slider's mass for flywheel effect.
+
+ If the slider's mass is greater then 0, it will continue
+ to move after the mouse button has been released. Its speed
+ decreases with time at a rate depending on the slider's mass.
+ A large mass means that it will continue to move for a
+ long time.
+
+ Derived widgets may overload this function to make it public.
+
+ \param val New mass in kg
+
+ \bug If the mass is smaller than 1g, it is set to zero.
+ The maximal mass is limited to 100kg.
+ \sa mass()
+*/
+void QwtAbstractSlider::setMass( double val )
+{
+ if ( val < 0.001 )
+ d_data->mass = 0.0;
+ else if ( val > 100.0 )
+ d_data->mass = 100.0;
+ else
+ d_data->mass = val;
+}
+
+/*!
+ \return mass
+ \sa setMass()
+*/
+double QwtAbstractSlider::mass() const
+{
+ return d_data->mass;
+}
+
+
+/*!
+ \brief Move the slider to a specified value
+
+ This function can be used to move the slider to a value
+ which is not an integer multiple of the step size.
+ \param val new value
+ \sa fitValue()
+*/
+void QwtAbstractSlider::setValue( double val )
+{
+ if ( d_data->scrollMode == ScrMouse )
+ stopMoving();
+ QwtDoubleRange::setValue( val );
+}
+
+
+/*!
+ \brief Set the slider's value to the nearest integer multiple
+ of the step size.
+
+ \param value Value
+ \sa setValue(), incValue()
+*/
+void QwtAbstractSlider::fitValue( double value )
+{
+ if ( d_data->scrollMode == ScrMouse )
+ stopMoving();
+ QwtDoubleRange::fitValue( value );
+}
+
+/*!
+ \brief Increment the value by a specified number of steps
+ \param steps number of steps
+ \sa setValue()
+*/
+void QwtAbstractSlider::incValue( int steps )
+{
+ if ( d_data->scrollMode == ScrMouse )
+ stopMoving();
+ QwtDoubleRange::incValue( steps );
+}
+
+/*!
+ \sa mouseOffset()
+*/
+void QwtAbstractSlider::setMouseOffset( double offset )
+{
+ d_data->mouseOffset = offset;
+}
+
+/*!
+ \sa setMouseOffset()
+*/
+double QwtAbstractSlider::mouseOffset() const
+{
+ return d_data->mouseOffset;
+}
+
+//! sa ScrollMode
+int QwtAbstractSlider::scrollMode() const
+{
+ return d_data->scrollMode;
+}
diff --git a/src/libpcp_qwt/src/qwt_abstract_slider.h b/src/libpcp_qwt/src/qwt_abstract_slider.h
new file mode 100644
index 0000000..d9facbb
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_abstract_slider.h
@@ -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_ABSTRACT_SLIDER_H
+#define QWT_ABSTRACT_SLIDER_H
+
+#include "qwt_global.h"
+#include "qwt_double_range.h"
+#include <qwidget.h>
+
+/*!
+ \brief An abstract base class for slider widgets
+
+ QwtAbstractSlider is a base class for
+ slider widgets. It handles mouse events
+ and updates the slider's value accordingly. Derived classes
+ only have to implement the getValue() and
+ getScrollMode() members, and should react to a
+ valueChange(), which normally requires repainting.
+*/
+
+class QWT_EXPORT QwtAbstractSlider : public QWidget, public QwtDoubleRange
+{
+ Q_OBJECT
+ Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
+ Q_PROPERTY( bool valid READ isValid WRITE setValid )
+ Q_PROPERTY( double mass READ mass WRITE setMass )
+ Q_PROPERTY( Qt::Orientation orientation
+ READ orientation WRITE setOrientation )
+
+public:
+ /*!
+ Scroll mode
+ \sa getScrollMode()
+ */
+ enum ScrollMode
+ {
+ //! Scrolling switched off. Don't change the value.
+ ScrNone,
+
+ /*!
+ Change the value while the user keeps the
+ button pressed and moves the mouse.
+ */
+ ScrMouse,
+
+ /*!
+ Automatic scrolling. Increment the value in the specified direction
+ as long as the user keeps the button pressed.
+ */
+ ScrTimer,
+
+ ScrDirect,
+
+ //! Automatic scrolling. Same as ScrTimer, but increment by page size.
+ ScrPage
+ };
+
+ explicit QwtAbstractSlider( Qt::Orientation, QWidget *parent = NULL );
+ virtual ~QwtAbstractSlider();
+
+ void setUpdateTime( int t );
+ void stopMoving();
+ void setTracking( bool enable );
+
+ virtual void setMass( double val );
+ virtual double mass() const;
+
+ virtual void setOrientation( Qt::Orientation o );
+ Qt::Orientation orientation() const;
+
+ bool isReadOnly() const;
+
+ /*
+ Wrappers for QwtDblRange::isValid/QwtDblRange::setValid made
+ to be available as Q_PROPERTY in the designer.
+ */
+
+ /*!
+ \sa QwtDblRange::isValid()
+ */
+ bool isValid() const
+ {
+ return QwtDoubleRange::isValid();
+ }
+
+ /*!
+ \param valid true/false
+ \sa QwtDblRange::isValid()
+ */
+ void setValid( bool valid )
+ {
+ QwtDoubleRange::setValid( valid );
+ }
+
+public Q_SLOTS:
+ virtual void setValue( double val );
+ virtual void fitValue( double val );
+ virtual void incValue( int steps );
+
+ virtual void setReadOnly( bool );
+
+Q_SIGNALS:
+
+ /*!
+ \brief Notify a change of value.
+
+ In the default setting
+ (tracking enabled), this signal will be emitted every
+ time the value changes ( see setTracking() ).
+ \param value new value
+ */
+ void valueChanged( double value );
+
+ /*!
+ This signal is emitted when the user presses the
+ movable part of the slider (start ScrMouse Mode).
+ */
+ 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
+ */
+ void sliderMoved( double value );
+
+protected:
+ virtual void setPosition( const QPoint & );
+ virtual void valueChange();
+
+ virtual void timerEvent( QTimerEvent *e );
+ virtual void mousePressEvent( QMouseEvent *e );
+ virtual void mouseReleaseEvent( QMouseEvent *e );
+ virtual void mouseMoveEvent( QMouseEvent *e );
+ virtual void keyPressEvent( QKeyEvent *e );
+ virtual void wheelEvent( QWheelEvent *e );
+
+ /*!
+ \brief Determine the value corresponding to a specified poind
+
+ This is an abstract virtual function which is called when
+ the user presses or releases a mouse button or moves the
+ mouse. It has to be implemented by the derived class.
+ \param p point
+ */
+ virtual double getValue( const QPoint & p ) = 0;
+
+ /*!
+ \brief Determine what to do when the user presses a mouse button.
+
+ This function is abstract and has to be implemented by derived classes.
+ It is called on a mousePress event. The derived class can determine
+ what should happen next in dependence of the position where the mouse
+ was pressed by returning scrolling mode and direction.
+
+ \param pos point where the mouse was pressed
+ \retval scrollMode The scrolling mode
+ \retval direction direction: 1, 0, or -1.
+ */
+ virtual void getScrollMode( const QPoint &pos,
+ ScrollMode &scrollMode, int &direction ) const = 0;
+
+ void setMouseOffset( double );
+ double mouseOffset() const;
+
+ int scrollMode() const;
+
+private:
+ void buttonReleased();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_analog_clock.cpp b/src/libpcp_qwt/src/qwt_analog_clock.cpp
new file mode 100644
index 0000000..fe723d1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_analog_clock.cpp
@@ -0,0 +1,228 @@
+/* -*- 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 <qmath.h>
+
+/*!
+ Constructor
+ \param parent Parent widget
+*/
+QwtAnalogClock::QwtAnalogClock( QWidget *parent ):
+ QwtDial( parent )
+{
+ initClock();
+}
+
+void QwtAnalogClock::initClock()
+{
+ setWrapping( true );
+ setReadOnly( true );
+
+ setOrigin( 270.0 );
+ setRange( 0.0, 60.0 * 60.0 * 12.0 ); // seconds
+ setScale( -1, 5, 60.0 * 60.0 );
+
+ setScaleComponents(
+ QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels );
+ setScaleTicks( 1, 0, 8 );
+ scaleDraw()->setSpacing( 8 );
+
+ 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( ( 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 clockhand
+ \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
+
+ This is the same as QwtAnalogClock::setTime(), but Qt < 3.0
+ can't handle default parameters for slots.
+*/
+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 );
+}
+
+/*!
+ Find the scale label for a given value
+
+ \param value Value
+ \return Label
+*/
+QwtText QwtAnalogClock::scaleLabel( double value ) const
+{
+ if ( qFuzzyCompare( value + 1.0, 1.0 ) )
+ value = 60.0 * 60.0 * 12.0;
+
+ return QString::number( qRound( value / ( 60.0 * 60.0 ) ) );
+}
+
+/*!
+ \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 &center,
+ 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++ )
+ {
+ double d = angle[hand];
+ if ( direction() == Clockwise )
+ d = 360.0 - d;
+
+ d -= origin();
+
+ drawHand( painter, ( 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 &center, 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 );
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_analog_clock.h b/src/libpcp_qwt/src/qwt_analog_clock.h
new file mode 100644
index 0000000..f20c3f1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_analog_clock.h
@@ -0,0 +1,96 @@
+/* -*- 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
+ \verbatim #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);
+
+ \endverbatim
+
+ Qwt is missing a set of good looking hands.
+ Contributions are very welcome.
+
+ \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();
+
+ virtual void setHand( Hand, QwtDialNeedle * );
+ const QwtDialNeedle *hand( Hand ) const;
+ QwtDialNeedle *hand( Hand );
+
+public Q_SLOTS:
+ void setCurrentTime();
+ void setTime( const QTime & = QTime::currentTime() );
+
+protected:
+ virtual QwtText scaleLabel( double ) const;
+
+ 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:
+ virtual void setNeedle( QwtDialNeedle * );
+ void initClock();
+
+ QwtDialNeedle *d_hand[NHands];
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_arrow_button.cpp b/src/libpcp_qwt/src/qwt_arrow_button.cpp
new file mode 100644
index 0000000..f451b44
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_arrow_button.cpp
@@ -0,0 +1,332 @@
+/* -*- 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::ArowType 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 rect 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 on 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 rect
+
+ \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->setPen( palette().color( QPalette::ButtonText ) );
+ 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 rect 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 );
+}
diff --git a/src/libpcp_qwt/src/qwt_arrow_button.h b/src/libpcp_qwt/src/qwt_arrow_button.h
new file mode 100644
index 0000000..ae436fe
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_arrow_button.h
@@ -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 *p );
+ 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
diff --git a/src/libpcp_qwt/src/qwt_clipper.cpp b/src/libpcp_qwt/src/qwt_clipper.cpp
new file mode 100644
index 0000000..fea3fd4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_clipper.cpp
@@ -0,0 +1,486 @@
+/* -*- 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>
+
+#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, ( 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, ( 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( ( 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( ( 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 )
+ qFree( m_buffer );
+ }
+
+ inline void setPoints( int numPoints, const Point *points )
+ {
+ reserve( numPoints );
+
+ m_size = numPoints;
+ qMemCopy( 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 = ( Point * ) qRealloc(
+ 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() );
+ qMemCopy( 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( ( 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 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() devides 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 &center, double radius )
+{
+ QwtCircleClipper clipper( clipRect );
+ return clipper.clipCircle( center, radius );
+}
diff --git a/src/libpcp_qwt/src/qwt_clipper.h b/src/libpcp_qwt/src/qwt_clipper.h
new file mode 100644
index 0000000..98316d3
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_clipper.h
@@ -0,0 +1,37 @@
+/* -*- 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 algos
+*/
+
+class QWT_EXPORT QwtClipper
+{
+public:
+ static QPolygon clipPolygon( const QRect &,
+ 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
diff --git a/src/libpcp_qwt/src/qwt_color_map.cpp b/src/libpcp_qwt/src/qwt_color_map.cpp
new file mode 100644
index 0000000..4318e5a
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_color_map.cpp
@@ -0,0 +1,440 @@
+/* -*- 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()
+ {
+ _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.rgb() )
+ {
+ r = qRed( rgb );
+ g = qGreen( rgb );
+ b = qBlue( rgb );
+ }
+
+ double pos;
+ QRgb rgb;
+ int r, g, b;
+ };
+
+ inline int findUpper( double pos ) const;
+ QVector<ColorStop> _stops;
+};
+
+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 ( _stops.size() == 0 )
+ {
+ index = 0;
+ _stops.resize( 1 );
+ }
+ else
+ {
+ index = findUpper( pos );
+ if ( index == _stops.size() ||
+ qAbs( _stops[index].pos - pos ) >= 0.001 )
+ {
+ _stops.resize( _stops.size() + 1 );
+ for ( int i = _stops.size() - 1; i > index; i-- )
+ _stops[i] = _stops[i-1];
+ }
+ }
+
+ _stops[index] = ColorStop( pos, color );
+}
+
+inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
+{
+ QVector<double> positions( _stops.size() );
+ for ( int i = 0; i < _stops.size(); i++ )
+ positions[i] = _stops[i].pos;
+ return positions;
+}
+
+inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
+{
+ int index = 0;
+ int n = _stops.size();
+
+ const ColorStop *stops = _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 _stops[0].rgb;
+ if ( pos >= 1.0 )
+ return _stops[ _stops.size() - 1 ].rgb;
+
+ const int index = findUpper( pos );
+ if ( mode == FixedColors )
+ {
+ return _stops[index-1].rgb;
+ }
+ else
+ {
+ const ColorStop &s1 = _stops[index-1];
+ const ColorStop &s2 = _stops[index];
+
+ const double ratio = ( pos - s1.pos ) / ( s2.pos - s1.pos );
+
+ const int r = s1.r + qRound( ratio * ( s2.r - s1.r ) );
+ const int g = s1.g + qRound( ratio * ( s2.g - s1.g ) );
+ const int b = s1.b + qRound( ratio * ( s2.b - s1.b ) );
+
+ 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 of the coor 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 all 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
+*/
+QRgb QwtLinearColorMap::rgb(
+ const QwtInterval &interval, double value ) const
+{
+ if ( qIsNaN(value) )
+ return qRgba(0, 0, 0, 0);
+
+ const double width = interval.width();
+
+ double ratio = 0.0;
+ if ( width > 0.0 )
+ ratio = ( value - interval.minValue() ) / width;
+
+ return d_data->colorStops.rgb( d_data->mode, ratio );
+}
+
+/*!
+ Map a value of a given interval into a color index, between 0 and 255
+
+ \param interval Range for all values
+ \param value Value to map into a color index
+*/
+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 ( unsigned char )255;
+
+ const double ratio = ( value - interval.minValue() ) / width;
+
+ unsigned char index;
+ if ( d_data->mode == FixedColors )
+ index = ( unsigned char )( ratio * 255 ); // always floor
+ else
+ index = ( unsigned char )qRound( ratio * 255 );
+
+ return index;
+}
+
+class QwtAlphaColorMap::PrivateData
+{
+public:
+ QColor color;
+ QRgb rgb;
+};
+
+
+/*!
+ Constructor
+ \param color Color of the map
+*/
+QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
+ QwtColorMap( QwtColorMap::RGB )
+{
+ d_data = new PrivateData;
+ d_data->color = color;
+ d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
+}
+
+//! 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();
+}
+
+/*!
+ \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
+{
+ const double width = interval.width();
+ if ( !qIsNaN(value) && width >= 0.0 )
+ {
+ const double ratio = ( value - interval.minValue() ) / width;
+ int alpha = qRound( 255 * ratio );
+ if ( alpha < 0 )
+ alpha = 0;
+ if ( alpha > 255 )
+ alpha = 255;
+
+ return d_data->rgb | ( alpha << 24 );
+ }
+ return d_data->rgb;
+}
+
+/*!
+ 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;
+}
diff --git a/src/libpcp_qwt/src/qwt_color_map.h b/src/libpcp_qwt/src/qwt_color_map.h
new file mode 100644
index 0000000..e754830
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_color_map.h
@@ -0,0 +1,198 @@
+/* -*- 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 QRgb 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 &from, const QColor &to,
+ 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 variies 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( rgb( interval, value ) );
+ }
+ else
+ {
+ const unsigned int index = colorIndex( interval, value );
+ return colorTable( interval )[index]; // slow
+ }
+}
+
+/*!
+ \return Intended format of the color map
+ \sa Format
+*/
+inline QwtColorMap::Format QwtColorMap::format() const
+{
+ return d_format;
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_column_symbol.cpp b/src/libpcp_qwt/src/qwt_column_symbol.cpp
new file mode 100644
index 0000000..ecbcd9a
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_column_symbol.cpp
@@ -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 drawBox( 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 drawPanel( 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 ),
+ lineWidth( 2 )
+ {
+ palette = QPalette( Qt::gray );
+ }
+
+ 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:
+ {
+ ::drawPanel( painter, r, d_data->palette, d_data->lineWidth );
+ break;
+ }
+ case QwtColumnSymbol::Plain:
+ {
+ ::drawBox( painter, r, d_data->palette, d_data->lineWidth );
+ break;
+ }
+ default:
+ {
+ painter->fillRect( r, d_data->palette.window() );
+ }
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_column_symbol.h b/src/libpcp_qwt/src/qwt_column_symbol.h
new file mode 100644
index 0000000..3c278f1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_column_symbol.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_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 und 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 style );
+ 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
diff --git a/src/libpcp_qwt/src/qwt_compass.cpp b/src/libpcp_qwt/src/qwt_compass.cpp
new file mode 100644
index 0000000..5ee3e4e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_compass.cpp
@@ -0,0 +1,292 @@
+/* -*- 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>
+
+class QwtCompass::PrivateData
+{
+public:
+ PrivateData():
+ rose( NULL )
+ {
+ }
+
+ ~PrivateData()
+ {
+ delete rose;
+ }
+
+ QwtCompassRose *rose;
+ QMap<double, QString> labelMap;
+};
+
+/*!
+ \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 )
+{
+ initCompass();
+}
+
+//! Destructor
+QwtCompass::~QwtCompass()
+{
+ delete d_data;
+}
+
+void QwtCompass::initCompass()
+{
+ d_data = new PrivateData;
+
+ // Only labels, no backbone, no ticks
+ setScaleComponents( QwtAbstractScaleDraw::Labels );
+
+ setOrigin( 270.0 );
+ setWrapping( true );
+
+
+ d_data->labelMap.insert( 0.0, QString::fromLatin1( "N" ) );
+ d_data->labelMap.insert( 45.0, QString::fromLatin1( "NE" ) );
+ d_data->labelMap.insert( 90.0, QString::fromLatin1( "E" ) );
+ d_data->labelMap.insert( 135.0, QString::fromLatin1( "SE" ) );
+ d_data->labelMap.insert( 180.0, QString::fromLatin1( "S" ) );
+ d_data->labelMap.insert( 225.0, QString::fromLatin1( "SW" ) );
+ d_data->labelMap.insert( 270.0, QString::fromLatin1( "W" ) );
+ d_data->labelMap.insert( 315.0, QString::fromLatin1( "NW" ) );
+
+#if 0
+ d_data->labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) );
+ d_data->labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) );
+ d_data->labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) );
+ d_data->labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) );
+ d_data->labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) );
+ d_data->labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) );
+ d_data->labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) );
+ d_data->labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) );
+#endif
+}
+
+/*!
+ 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 &center, 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 &center,
+ 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 );
+ }
+}
+
+/*!
+ \return map, mapping values to labels
+ \sa setLabelMap()
+*/
+const QMap<double, QString> &QwtCompass::labelMap() const
+{
+ return d_data->labelMap;
+}
+
+/*!
+ \return map, mapping values to labels
+ \sa setLabelMap()
+*/
+QMap<double, QString> &QwtCompass::labelMap()
+{
+ return d_data->labelMap;
+}
+
+/*!
+ \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 QwtCompass::setLabelMap( const QMap<double, QString> &map )
+{
+ d_data->labelMap = map;
+}
+
+/*!
+ Map a value to a corresponding label
+ \param value Value that will be mapped
+ \return Label, or QString::null
+
+ label() looks in a map for a corresponding label for value
+ or return an null text.
+ \sa labelMap(), setLabelMap()
+*/
+
+QwtText QwtCompass::scaleLabel( double value ) const
+{
+ if ( qFuzzyCompare( value + 1.0, 1.0 ) )
+ value = 0.0;
+
+ if ( value < 0.0 )
+ value += 360.0;
+
+ if ( d_data->labelMap.contains( value ) )
+ return d_data->labelMap[value];
+
+ return QwtText();
+}
diff --git a/src/libpcp_qwt/src/qwt_compass.h b/src/libpcp_qwt/src/qwt_compass.h
new file mode 100644
index 0000000..a1044b7
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_compass.h
@@ -0,0 +1,65 @@
+/* -*- 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 <qstring.h>
+#include <qmap.h>
+
+class QwtCompassRose;
+
+/*!
+ \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();
+
+ const QMap<double, QString> &labelMap() const;
+ QMap<double, QString> &labelMap();
+ void setLabelMap( const QMap<double, QString> &map );
+
+protected:
+ virtual QwtText scaleLabel( double value ) const;
+
+ virtual void drawRose( QPainter *, const QPointF &center,
+ double radius, double north, QPalette::ColorGroup ) const;
+
+ virtual void drawScaleContents( QPainter *,
+ const QPointF &center, double radius ) const;
+
+ virtual void keyPressEvent( QKeyEvent * );
+
+private:
+ void initCompass();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_compass_rose.cpp b/src/libpcp_qwt/src/qwt_compass_rose.cpp
new file mode 100644
index 0000000..375a5bd
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_compass_rose.cpp
@@ -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_compass_rose.h"
+#include "qwt_point_polar.h"
+#include "qwt_painter.h"
+#include <qpainter.h>
+
+static QPointF qwtIntersection(
+ QPointF p11, QPointF p12, QPointF p21, QPointF p22 )
+{
+ const QLineF line1( p11, p12 );
+ const QLineF line2( p21, p22 );
+
+ QPointF pos;
+ if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection )
+ return QPointF();
+
+ return pos;
+}
+
+class QwtSimpleCompassRose::PrivateData
+{
+public:
+ PrivateData():
+ width( 0.2 ),
+ numThorns( 8 ),
+ numThornLevels( -1 ),
+ shrinkFactor( 0.9 )
+ {
+ }
+
+ double width;
+ int numThorns;
+ int numThornLevels;
+ double shrinkFactor;
+};
+
+/*!
+ Constructor
+
+ \param numThorns Number of thorns
+ \param numThornLevels Number of thorn levels
+*/
+QwtSimpleCompassRose::QwtSimpleCompassRose(
+ int numThorns, int numThornLevels )
+{
+ d_data = new PrivateData();
+ d_data->numThorns = numThorns;
+ d_data->numThornLevels = numThornLevels;
+
+ const QColor dark( 128, 128, 255 );
+ const QColor light( 192, 255, 255 );
+
+ QPalette palette;
+ palette.setColor( QPalette::Dark, dark );
+ palette.setColor( QPalette::Light, light );
+
+ setPalette( palette );
+}
+
+//! Destructor
+QwtSimpleCompassRose::~QwtSimpleCompassRose()
+{
+ delete d_data;
+}
+
+/*!
+ Set the Factor how to shrink the thorns with each level
+ The default value is 0.9.
+
+ \sa shrinkFactor()
+*/
+void QwtSimpleCompassRose::setShrinkFactor( double factor )
+{
+ d_data->shrinkFactor = factor;
+}
+
+/*!
+ \return Factor how to shrink the thorns with each level
+ \sa setShrinkFactor()
+*/
+double QwtSimpleCompassRose::shrinkFactor() const
+{
+ return d_data->shrinkFactor;
+}
+
+/*!
+ Draw the rose
+
+ \param painter Painter
+ \param center Center point
+ \param radius Radius of the rose
+ \param north Position
+ \param cg Color group
+*/
+void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF &center,
+ double radius, double north, QPalette::ColorGroup cg ) const
+{
+ QPalette pal = palette();
+ pal.setCurrentColorGroup( cg );
+
+ drawRose( painter, pal, center, radius, north, d_data->width,
+ d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor );
+}
+
+/*!
+ Draw the rose
+
+ \param painter Painter
+ \param palette Palette
+ \param center Center of the rose
+ \param radius Radius of the rose
+ \param north Position pointing to north
+ \param width Width of the rose
+ \param numThorns Number of thorns
+ \param numThornLevels Number of thorn levels
+ \param shrinkFactor Factor to shrink the thorns with each level
+*/
+void QwtSimpleCompassRose::drawRose(
+ QPainter *painter,
+ const QPalette &palette,
+ const QPointF &center, double radius, double north, double width,
+ int numThorns, int numThornLevels, double shrinkFactor )
+{
+ if ( numThorns < 4 )
+ numThorns = 4;
+
+ if ( numThorns % 4 )
+ numThorns += 4 - numThorns % 4;
+
+ if ( numThornLevels <= 0 )
+ numThornLevels = numThorns / 4;
+
+ if ( shrinkFactor >= 1.0 )
+ shrinkFactor = 1.0;
+
+ if ( shrinkFactor <= 0.5 )
+ shrinkFactor = 0.5;
+
+ painter->save();
+
+ painter->setPen( Qt::NoPen );
+
+ for ( int j = 1; j <= numThornLevels; j++ )
+ {
+ double step = qPow( 2.0, j ) * M_PI / numThorns;
+ if ( step > M_PI_2 )
+ break;
+
+ double r = radius;
+ for ( int k = 0; k < 3; k++ )
+ {
+ if ( j + k < numThornLevels )
+ r *= shrinkFactor;
+ }
+
+ double leafWidth = r * width;
+ if ( 2.0 * M_PI / step > 32 )
+ leafWidth = 16;
+
+ const double origin = north / 180.0 * M_PI;
+ for ( double angle = origin;
+ angle < 2.0 * M_PI + origin; angle += step )
+ {
+ const QPointF p = qwtPolar2Pos( center, r, angle );
+ const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 );
+ const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 );
+ const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 );
+ const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 );
+
+ QPainterPath darkPath;
+ darkPath.moveTo( center );
+ darkPath.lineTo( p );
+ darkPath.lineTo( qwtIntersection( center, p3, p1, p ) );
+
+ painter->setBrush( palette.brush( QPalette::Dark ) );
+ painter->drawPath( darkPath );
+
+ QPainterPath lightPath;
+ lightPath.moveTo( center );
+ lightPath.lineTo( p );
+ lightPath.lineTo( qwtIntersection( center, p4, p2, p ) );
+
+ painter->setBrush( palette.brush( QPalette::Light ) );
+ painter->drawPath( lightPath );
+ }
+ }
+ painter->restore();
+}
+
+/*!
+ Set the width of the rose heads. Lower value make thinner heads.
+ The range is limited from 0.03 to 0.4.
+
+ \param width Width
+*/
+void QwtSimpleCompassRose::setWidth( double width )
+{
+ d_data->width = width;
+ if ( d_data->width < 0.03 )
+ d_data->width = 0.03;
+
+ if ( d_data->width > 0.4 )
+ d_data->width = 0.4;
+}
+
+//! \sa setWidth()
+double QwtSimpleCompassRose::width() const
+{
+ return d_data->width;
+}
+
+/*!
+ Set the number of thorns on one level
+ The number is aligned to a multiple of 4, with a minimum of 4
+
+ \param numThorns Number of thorns
+ \sa numThorns(), setNumThornLevels()
+*/
+void QwtSimpleCompassRose::setNumThorns( int numThorns )
+{
+ if ( numThorns < 4 )
+ numThorns = 4;
+
+ if ( numThorns % 4 )
+ numThorns += 4 - numThorns % 4;
+
+ d_data->numThorns = numThorns;
+}
+
+/*!
+ \return Number of thorns
+ \sa setNumThorns(), setNumThornLevels()
+*/
+int QwtSimpleCompassRose::numThorns() const
+{
+ return d_data->numThorns;
+}
+
+/*!
+ Set the of thorns levels
+
+ \param numThornLevels Number of thorns levels
+ \sa setNumThorns(), numThornLevels()
+*/
+void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels )
+{
+ d_data->numThornLevels = numThornLevels;
+}
+
+/*!
+ \return Number of thorn levels
+ \sa setNumThorns(), setNumThornLevels()
+*/
+int QwtSimpleCompassRose::numThornLevels() const
+{
+ return d_data->numThornLevels;
+}
diff --git a/src/libpcp_qwt/src/qwt_compass_rose.h b/src/libpcp_qwt/src/qwt_compass_rose.h
new file mode 100644
index 0000000..9b715df
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_compass_rose.h
@@ -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 &center, 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 w );
+ double width() const;
+
+ void setNumThorns( int count );
+ int numThorns() const;
+
+ void setNumThornLevels( int count );
+ int numThornLevels() const;
+
+ void setShrinkFactor( double factor );
+ double shrinkFactor() const;
+
+ virtual void draw( QPainter *, const QPointF &center, double radius,
+ double north, QPalette::ColorGroup = QPalette::Active ) const;
+
+ static void drawRose( QPainter *, const QPalette &,
+ const QPointF &center, double radius, double origin, double width,
+ int numThorns, int numThornLevels, double shrinkFactor );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_compat.h b/src/libpcp_qwt/src/qwt_compat.h
new file mode 100644
index 0000000..c97cf6b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_compat.h
@@ -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
diff --git a/src/libpcp_qwt/src/qwt_counter.cpp b/src/libpcp_qwt/src/qwt_counter.cpp
new file mode 100644
index 0000000..2c7a895
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_counter.cpp
@@ -0,0 +1,603 @@
+/* -*- 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():
+ editable( true )
+ {
+ increment[Button1] = 1;
+ increment[Button2] = 10;
+ increment[Button3] = 100;
+ }
+
+ QwtArrowButton *buttonDown[ButtonCnt];
+ QwtArrowButton *buttonUp[ButtonCnt];
+ QLineEdit *valueEdit;
+
+ int increment[ButtonCnt];
+ int numButtons;
+
+ bool editable;
+};
+
+/*!
+ 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, 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 from lineedit
+void QwtCounter::textChanged()
+{
+ if ( !d_data->editable )
+ return;
+
+ bool converted = false;
+
+ const double value = d_data->valueEdit->text().toDouble( &converted );
+ if ( converted )
+ setValue( value );
+}
+
+/**
+ \brief Allow/disallow the user to manually edit the value
+
+ \param editable true enables editing
+ \sa editable()
+*/
+void QwtCounter::setEditable( bool editable )
+{
+ if ( editable == d_data->editable )
+ return;
+
+ d_data->editable = editable;
+ d_data->valueEdit->setReadOnly( !editable );
+}
+
+//! returns whether the line edit is edatble. (default is yes)
+bool QwtCounter::editable() const
+{
+ return d_data->editable;
+}
+
+/*!
+ Handle PolishRequest events
+ \param event 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 minValue()
+ - Ctrl + Qt::Key_End\n
+ Step to maxValue()
+ - 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( minValue() );
+ else
+ accepted = false;
+ break;
+ }
+ case Qt::Key_End:
+ {
+ if ( event->modifiers() & Qt::ControlModifier )
+ setValue( maxValue() );
+ else
+ accepted = false;
+ break;
+ }
+ case Qt::Key_Up:
+ {
+ incValue( d_data->increment[0] );
+ break;
+ }
+ case Qt::Key_Down:
+ {
+ incValue( -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;
+ incValue( 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;
+
+ int delta = event->delta();
+ if ( delta >= 2 * wheel_delta )
+ delta /= 2; // Never saw an abs(delta) < 240
+
+ incValue( delta / wheel_delta * increment );
+}
+
+/*!
+ Specify the number of steps by which the value
+ is incremented or decremented when a specified button
+ is pushed.
+
+ \param button Button index
+ \param nSteps Number of steps
+
+ \sa incSteps()
+*/
+void QwtCounter::setIncSteps( QwtCounter::Button button, int nSteps )
+{
+ if ( button >= 0 && button < ButtonCnt )
+ d_data->increment[button] = nSteps;
+}
+
+/*!
+ \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 < ButtonCnt )
+ return d_data->increment[button];
+
+ return 0;
+}
+
+/*!
+ \brief Set a new value
+
+ Calls QwtDoubleRange::setValue and does all visual updates.
+
+ \param value New value
+ \sa QwtDoubleRange::setValue()
+*/
+
+void QwtCounter::setValue( double value )
+{
+ QwtDoubleRange::setValue( value );
+
+ showNum( this->value() );
+ updateButtons();
+}
+
+/*!
+ \brief Notify a change of value
+*/
+void QwtCounter::valueChange()
+{
+ if ( isValid() )
+ showNum( value() );
+ else
+ d_data->valueEdit->setText( QString::null );
+
+ updateButtons();
+
+ if ( isValid() )
+ Q_EMIT valueChanged( 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 ( 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() > minValue() );
+ d_data->buttonUp[i]->setEnabled( value() < maxValue() );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
+ {
+ d_data->buttonDown[i]->setEnabled( false );
+ d_data->buttonUp[i]->setEnabled( false );
+ }
+ }
+}
+
+/*!
+ \brief Specify the number of buttons on each side of the label
+ \param numButtons Number of buttons
+*/
+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.
+*/
+int QwtCounter::numButtons() const
+{
+ return d_data->numButtons;
+}
+
+/*!
+ Display number string
+
+ \param number Number
+*/
+void QwtCounter::showNum( 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() )
+ incValue( d_data->increment[i] );
+
+ if ( d_data->buttonDown[i] == sender() )
+ incValue( -d_data->increment[i] );
+ }
+}
+
+//! Button released
+void QwtCounter::btnReleased()
+{
+ Q_EMIT buttonReleased( value() );
+}
+
+/*!
+ \brief Notify change of range
+
+ This function updates the enabled property of
+ all buttons contained in QwtCounter.
+*/
+void QwtCounter::rangeChange()
+{
+ updateButtons();
+}
+
+//! A size hint
+QSize QwtCounter::sizeHint() const
+{
+ QString tmp;
+
+ int w = tmp.setNum( minValue() ).length();
+ int w1 = tmp.setNum( maxValue() ).length();
+ if ( w1 > w )
+ w = w1;
+ w1 = tmp.setNum( minValue() + step() ).length();
+ if ( w1 > w )
+ w = w1;
+ w1 = tmp.setNum( maxValue() - step() ).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 );
+}
+
+//! returns the step size
+double QwtCounter::step() const
+{
+ return QwtDoubleRange::step();
+}
+
+/*!
+ Set the step size
+ \param stepSize Step size
+ \sa QwtDoubleRange::setStep()
+*/
+void QwtCounter::setStep( double stepSize )
+{
+ QwtDoubleRange::setStep( stepSize );
+}
+
+//! returns the minimum value of the range
+double QwtCounter::minValue() const
+{
+ return QwtDoubleRange::minValue();
+}
+
+/*!
+ Set the minimum value of the range
+
+ \param value Minimum value
+ \sa setMaxValue(), minValue()
+*/
+void QwtCounter::setMinValue( double value )
+{
+ setRange( value, maxValue(), step() );
+}
+
+//! returns the maximum value of the range
+double QwtCounter::maxValue() const
+{
+ return QwtDoubleRange::maxValue();
+}
+
+/*!
+ Set the maximum value of the range
+
+ \param value Maximum value
+ \sa setMinValue(), maxVal()
+*/
+void QwtCounter::setMaxValue( double value )
+{
+ setRange( minValue(), value, step() );
+}
+
+/*!
+ Set the number of increment steps for button 1
+ \param nSteps Number of steps
+*/
+void QwtCounter::setStepButton1( int nSteps )
+{
+ setIncSteps( Button1, nSteps );
+}
+
+//! returns the number of increment steps for button 1
+int QwtCounter::stepButton1() const
+{
+ return incSteps( Button1 );
+}
+
+/*!
+ Set the number of increment steps for button 2
+ \param nSteps Number of steps
+*/
+void QwtCounter::setStepButton2( int nSteps )
+{
+ setIncSteps( Button2, nSteps );
+}
+
+//! returns the number of increment steps for button 2
+int QwtCounter::stepButton2() const
+{
+ return incSteps( Button2 );
+}
+
+/*!
+ Set the number of increment steps for button 3
+ \param nSteps Number of steps
+*/
+void QwtCounter::setStepButton3( int nSteps )
+{
+ setIncSteps( Button3, nSteps );
+}
+
+//! returns the number of increment steps for button 3
+int QwtCounter::stepButton3() const
+{
+ return incSteps( Button3 );
+}
+
+//! \return Current value
+double QwtCounter::value() const
+{
+ return QwtDoubleRange::value();
+}
+
diff --git a/src/libpcp_qwt/src/qwt_counter.h b/src/libpcp_qwt/src/qwt_counter.h
new file mode 100644
index 0000000..459fdf9
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_counter.h
@@ -0,0 +1,148 @@
+/* -*- 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 "qwt_double_range.h"
+#include <qwidget.h>
+
+/*!
+ \brief The Counter Widget
+
+ A Counter consists of a lineEdit displaying a number and
+ one ore more (up to three) push buttons on each side
+ of the lineEdit 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. The range can be specified using setRange().
+ 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, 1.0); // From 0.0 to 100, step 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)), my_class, SLOT(newValue(double)));
+\endcode
+ */
+
+class QWT_EXPORT QwtCounter : public QWidget, public QwtDoubleRange
+{
+ Q_OBJECT
+
+ Q_PROPERTY( int numButtons READ numButtons WRITE setNumButtons )
+ Q_PROPERTY( double basicstep READ step WRITE setStep )
+ Q_PROPERTY( double minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( double maxValue READ maxValue WRITE setMaxValue )
+ 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( double value READ value WRITE setValue )
+ Q_PROPERTY( bool editable READ editable WRITE setEditable )
+
+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();
+
+ bool editable() const;
+ void setEditable( bool );
+
+ void setNumButtons( int n );
+ int numButtons() const;
+
+ void setIncSteps( QwtCounter::Button btn, int nSteps );
+ int incSteps( QwtCounter::Button btn ) const;
+
+ virtual void setValue( double );
+ virtual QSize sizeHint() const;
+
+ // a set of dummies to help the designer
+
+ double step() const;
+ void setStep( double s );
+
+ double minValue() const;
+ void setMinValue( double m );
+
+ double maxValue() const;
+ void setMaxValue( double m );
+
+ void setStepButton1( int nSteps );
+ int stepButton1() const;
+
+ void setStepButton2( int nSteps );
+ int stepButton2() const;
+
+ void setStepButton3( int nSteps );
+ int stepButton3() const;
+
+ virtual double value() const;
+
+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 * );
+ virtual void rangeChange();
+
+private Q_SLOTS:
+ void btnReleased();
+ void btnClicked();
+ void textChanged();
+
+private:
+ void initCounter();
+ void updateButtons();
+ void showNum( double );
+ virtual void valueChange();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_curve_fitter.cpp b/src/libpcp_qwt/src/qwt_curve_fitter.cpp
new file mode 100644
index 0000000..639a80d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_curve_fitter.cpp
@@ -0,0 +1,405 @@
+/* -*- 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 )
+ {
+ }
+
+ double tolerance;
+};
+
+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 accaptable
+ 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;
+}
+
+/*!
+ \param points Series of data points
+ \return Curve points
+*/
+QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const
+{
+ QStack<Line> stack;
+ stack.reserve( 500 );
+
+ const QPointF *p = points.data();
+ const int nPoints = points.size();
+
+ QVector<bool> usePoint( nPoints, false );
+
+ double distToSegment;
+
+ 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 maxDist = 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();
+ const double fromVecLength =
+ qSqrt( fromVecX * fromVecX + fromVecY * fromVecY );
+
+ if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
+ {
+ distToSegment = fromVecLength;
+ }
+ if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
+ {
+ distToSegment = fromVecLength;
+ }
+ else
+ {
+ const double toVecX = p[i].x() - p[r.to].x();
+ const double toVecY = p[i].y() - p[r.to].y();
+ const double toVecLength = qSqrt( toVecX * toVecX + toVecY * toVecY );
+ const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
+ if ( s < 0.0 )
+ distToSegment = toVecLength;
+ else
+ {
+ distToSegment = qSqrt( qFabs( toVecLength * toVecLength - s * s ) );
+ }
+ }
+
+ if ( maxDist < distToSegment )
+ {
+ maxDist = distToSegment;
+ nVertexIndexMaxDistance = i;
+ }
+ }
+ if ( maxDist <= d_data->tolerance )
+ {
+ usePoint[r.from] = true;
+ usePoint[r.to] = true;
+ }
+ else
+ {
+ stack.push( Line( r.from, nVertexIndexMaxDistance ) );
+ stack.push( Line( nVertexIndexMaxDistance, r.to ) );
+ }
+ }
+
+ int cnt = 0;
+
+ QPolygonF stripped( nPoints );
+ for ( int i = 0; i < nPoints; i++ )
+ {
+ if ( usePoint[i] )
+ stripped[cnt++] = p[i];
+ }
+ stripped.resize( cnt );
+ return stripped;
+}
diff --git a/src/libpcp_qwt/src/qwt_curve_fitter.h b/src/libpcp_qwt/src/qwt_curve_fitter.h
new file mode 100644
index 0000000..c9ae603
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_curve_fitter.h
@@ -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_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 size );
+ 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 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;
+
+ virtual QPolygonF fitCurve( const QPolygonF & ) const;
+
+private:
+ class Line;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_dial.cpp b/src/libpcp_qwt/src/qwt_dial.cpp
new file mode 100644
index 0000000..cf05561
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dial.cpp
@@ -0,0 +1,1156 @@
+/* -*- 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_painter.h"
+#include <qpainter.h>
+#include <qbitmap.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>
+
+#if QT_VERSION < 0x040601
+#define qAtan(x) ::atan(x)
+#endif
+
+class QwtDial::PrivateData
+{
+public:
+ PrivateData():
+ frameShadow( Sunken ),
+ lineWidth( 0 ),
+ mode( RotateNeedle ),
+ direction( Clockwise ),
+ origin( 90.0 ),
+ minScaleArc( 0.0 ),
+ maxScaleArc( 0.0 ),
+ scaleDraw( 0 ),
+ maxMajIntv( 36 ),
+ maxMinIntv( 10 ),
+ scaleStep( 0.0 ),
+ needle( 0 )
+ {
+ }
+
+ ~PrivateData()
+ {
+ delete scaleDraw;
+ delete needle;
+ }
+ Shadow frameShadow;
+ int lineWidth;
+
+ QwtDial::Mode mode;
+ QwtDial::Direction direction;
+
+ double origin;
+ double minScaleArc;
+ double maxScaleArc;
+
+ QwtDialScaleDraw *scaleDraw;
+ int maxMajIntv;
+ int maxMinIntv;
+ double scaleStep;
+
+ QwtDialNeedle *needle;
+
+ static double previousDir;
+};
+
+double QwtDial::PrivateData::previousDir = -1.0;
+
+/*!
+ Constructor
+
+ \param parent Parent dial widget
+*/
+QwtDialScaleDraw::QwtDialScaleDraw( QwtDial *parent ):
+ d_parent( parent ),
+ d_penWidth( 1.0 )
+{
+}
+
+/*!
+ Set the pen width used for painting the scale
+
+ \param penWidth Pen width
+ \sa penWidth(), QwtDial::drawScale()
+*/
+
+void QwtDialScaleDraw::setPenWidth( double penWidth )
+{
+ d_penWidth = qMax( penWidth, 0.0 );
+}
+
+/*!
+ \return Pen width used for painting the scale
+ \sa setPenWidth, QwtDial::drawScale()
+*/
+double QwtDialScaleDraw::penWidth() const
+{
+ return d_penWidth;
+}
+
+/*!
+ Call QwtDial::scaleLabel of the parent dial widget.
+
+ \param value Value to display
+
+ \sa QwtDial::scaleLabel()
+*/
+QwtText QwtDialScaleDraw::label( double value ) const
+{
+ if ( d_parent == NULL )
+ return QwtRoundScaleDraw::label( value );
+
+ return d_parent->scaleLabel( value );
+}
+
+/*!
+ \brief Constructor
+ \param parent Parent widget
+
+ Create a dial widget with no scale and no needle.
+ The default origin is 90.0 with no valid value. It accepts
+ mouse and keyboard inputs and has no step size. The default mode
+ is QwtDial::RotateNeedle.
+*/
+QwtDial::QwtDial( QWidget* parent ):
+ QwtAbstractSlider( Qt::Horizontal, parent )
+{
+ initDial();
+}
+
+void QwtDial::initDial()
+{
+ d_data = new PrivateData;
+
+ setFocusPolicy( Qt::TabFocus );
+
+ QPalette p = palette();
+ for ( int i = 0; i < QPalette::NColorGroups; i++ )
+ {
+ const QPalette::ColorGroup colorGroup = ( 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 );
+
+ d_data->scaleDraw = new QwtDialScaleDraw( this );
+ d_data->scaleDraw->setRadius( 0 );
+
+ setScaleArc( 0.0, 360.0 ); // scale as a full circle
+ setRange( 0.0, 360.0, 1.0, 10 ); // degrees as default
+}
+
+//! 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 )
+ {
+ 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
+
+ \param lineWidth Line width
+ \sa setFrameShadow()
+*/
+void QwtDial::setLineWidth( int lineWidth )
+{
+ if ( lineWidth < 0 )
+ lineWidth = 0;
+
+ if ( d_data->lineWidth != lineWidth )
+ {
+ 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 rect of the circle inside the frame
+ \sa setLineWidth(), scaleInnerRect(), boundingRect()
+*/
+QRectF QwtDial::innerRect() const
+{
+ const double lw = lineWidth();
+ return boundingRect().adjusted( lw, lw, -lw, -lw );
+}
+
+/*!
+ \return bounding rect of the dial including the frame
+ \sa setLineWidth(), scaleInnerRect(), innerRect()
+*/
+QRectF QwtDial::boundingRect() const
+{
+ const QRectF cr = contentsRect();
+
+ const double dim = qMin( cr.width(), cr.height() );
+
+ QRectF inner( 0, 0, dim, dim );
+ inner.moveCenter( cr.center() );
+
+ return inner;
+}
+
+/*!
+ \return rect inside the scale
+ \sa setLineWidth(), boundingRect(), innerRect()
+*/
+QRectF QwtDial::scaleInnerRect() const
+{
+ QRectF rect = innerRect();
+
+ if ( d_data->scaleDraw )
+ {
+ double scaleDist = qCeil( d_data->scaleDraw->extent( font() ) );
+ scaleDist++; // margin
+
+ rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
+ }
+
+ return rect;
+}
+
+/*!
+ \brief Change the mode of the meter.
+ \param mode New mode
+
+ The value of the meter is indicated by the difference
+ between north of the scale and the direction of the needle.
+ In case of QwtDial::RotateNeedle north is pointing
+ to the origin() and 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 )
+ {
+ d_data->mode = mode;
+ update();
+ }
+}
+
+/*!
+ \return mode of the dial.
+
+ The value of the dial is indicated by the difference
+ between the origin and the direction of the needle.
+ In case of QwtDial::RotateNeedle the scale arc is fixed
+ to the origin() and 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 setMode(), origin(), setScaleArc(), value()
+*/
+QwtDial::Mode QwtDial::mode() const
+{
+ return d_data->mode;
+}
+
+/*!
+ Sets whether it is possible to step the value from the highest value to
+ the lowest value and vice versa to on.
+
+ \param wrapping en/disables wrapping
+
+ \sa wrapping(), QwtDoubleRange::periodic()
+ \note The meaning of wrapping is like the wrapping property of QSpinBox,
+ but not like it is used in QDial.
+*/
+void QwtDial::setWrapping( bool wrapping )
+{
+ setPeriodic( wrapping );
+}
+
+/*!
+ wrapping() holds whether it is possible to step the value from the
+ highest value to the lowest value and vice versa.
+
+ \sa setWrapping(), QwtDoubleRange::setPeriodic()
+ \note The meaning of wrapping is like the wrapping property of QSpinBox,
+ but not like it is used in QDial.
+*/
+bool QwtDial::wrapping() const
+{
+ return periodic();
+}
+
+/*!
+ Set the direction of the dial (clockwise/counterclockwise)
+
+ \param direction Direction
+ \sa direction()
+*/
+void QwtDial::setDirection( Direction direction )
+{
+ if ( direction != d_data->direction )
+ {
+ d_data->direction = direction;
+ update();
+ }
+}
+
+/*!
+ \return Direction of the dial
+
+ The default direction of a dial is QwtDial::Clockwise
+
+ \sa setDirection()
+*/
+QwtDial::Direction QwtDial::direction() const
+{
+ return d_data->direction;
+}
+
+/*!
+ 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);
+
+ painter.setRenderHint( QPainter::Antialiasing, true );
+
+ painter.save();
+ drawContents( &painter );
+ painter.restore();
+
+ painter.save();
+ drawFrame( &painter );
+ painter.restore();
+
+ if ( hasFocus() )
+ drawFocusIndicator( &painter );
+}
+
+/*!
+ Draw a dotted round circle, if !isReadOnly()
+
+ \param painter Painter
+*/
+void QwtDial::drawFocusIndicator( QPainter *painter ) const
+{
+ if ( !isReadOnly() )
+ {
+ QRectF focusRect = innerRect();
+
+ const int margin = 2;
+ focusRect.adjust( margin, margin, -margin, -margin );
+
+ QColor color = palette().color( QPalette::Base );
+ if ( color.isValid() )
+ {
+ const QColor gray( Qt::gray );
+
+ int h, s, v;
+ color.getHsv( &h, &s, &v );
+ color = ( v > 128 ) ? gray.dark( 120 ) : gray.light( 120 );
+ }
+ else
+ color = Qt::darkGray;
+
+ painter->save();
+ painter->setBrush( Qt::NoBrush );
+ painter->setPen( QPen( color, 0, Qt::DotLine ) );
+ painter->drawEllipse( focusRect );
+ painter->restore();
+ }
+}
+
+/*!
+ Draw the frame around the dial
+
+ \param painter Painter
+ \sa lineWidth(), frameShadow()
+*/
+void QwtDial::drawFrame( QPainter *painter )
+{
+ if ( lineWidth() <= 0 )
+ return;
+
+ const double lw2 = 0.5 * lineWidth();
+
+ QRectF r = boundingRect();
+ r.adjust( lw2, lw2, -lw2, -lw2 );
+
+ QPen pen;
+
+ switch ( d_data->frameShadow )
+ {
+ case QwtDial::Raised:
+ case QwtDial::Sunken:
+ {
+ QColor c1 = palette().color( QPalette::Light );
+ QColor c2 = palette().color( QPalette::Dark );
+
+ if ( d_data->frameShadow == QwtDial::Sunken )
+ qSwap( c1, c2 );
+
+ QLinearGradient gradient( r.topLeft(), r.bottomRight() );
+ gradient.setColorAt( 0.0, c1 );
+#if 0
+ gradient.setColorAt( 0.3, c1 );
+ gradient.setColorAt( 0.7, c2 );
+#endif
+ gradient.setColorAt( 1.0, c2 );
+
+ pen = QPen( gradient, lineWidth() );
+ break;
+ }
+ default: // Plain
+ {
+ pen = QPen( palette().brush( QPalette::Dark ), lineWidth() );
+ }
+ }
+
+ painter->save();
+
+ painter->setPen( pen );
+ painter->setBrush( Qt::NoBrush );
+ painter->drawEllipse( r );
+
+ painter->restore();
+}
+
+/*!
+ \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();
+
+ double direction = d_data->origin;
+
+ if ( isValid() )
+ {
+ direction = d_data->minScaleArc;
+ if ( maxValue() > minValue() &&
+ d_data->maxScaleArc > d_data->minScaleArc )
+ {
+ const double ratio =
+ ( value() - minValue() ) / ( maxValue() - minValue() );
+ direction += ratio * ( d_data->maxScaleArc - d_data->minScaleArc );
+ }
+
+ if ( d_data->direction == QwtDial::CounterClockwise )
+ direction = d_data->maxScaleArc - ( direction - d_data->minScaleArc );
+
+ direction += d_data->origin;
+ if ( direction >= 360.0 )
+ direction -= 360.0;
+ else if ( direction < 0.0 )
+ direction += 360.0;
+ }
+
+ double origin = d_data->origin;
+ if ( mode() == RotateScale )
+ {
+ origin -= direction - d_data->origin;
+ direction = d_data->origin;
+ }
+
+ painter->save();
+ drawScale( painter, center, radius, origin,
+ d_data->minScaleArc, d_data->maxScaleArc );
+ painter->restore();
+
+ painter->save();
+ drawScaleContents( painter, center, radius );
+ painter->restore();
+
+ if ( isValid() )
+ {
+ QPalette::ColorGroup cg;
+ if ( isEnabled() )
+ cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
+ else
+ cg = QPalette::Disabled;
+
+ painter->save();
+ drawNeedle( painter, center, radius, direction, cg );
+ 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 cg ColorGroup
+*/
+void QwtDial::drawNeedle( QPainter *painter, const QPointF &center,
+ double radius, double direction, QPalette::ColorGroup cg ) const
+{
+ if ( d_data->needle )
+ {
+ direction = 360.0 - direction; // counter clockwise
+ d_data->needle->draw( painter, center, radius, direction, cg );
+ }
+}
+
+/*!
+ Draw the scale
+
+ \param painter Painter
+ \param center Center of the dial
+ \param radius Radius of the scale
+ \param origin Origin of the scale
+ \param minArc Minimum of the arc
+ \param maxArc Minimum of the arc
+
+ \sa QwtRoundScaleDraw::setAngleRange()
+*/
+void QwtDial::drawScale( QPainter *painter, const QPointF &center,
+ double radius, double origin, double minArc, double maxArc ) const
+{
+ if ( d_data->scaleDraw == NULL )
+ return;
+
+ origin -= 270.0; // hardcoded origin of QwtScaleDraw
+
+ double angle = maxArc - minArc;
+ if ( angle > 360.0 )
+ angle = ::fmod( angle, 360.0 );
+
+ minArc += origin;
+ if ( minArc < -360.0 )
+ minArc = ::fmod( minArc, 360.0 );
+
+ maxArc = minArc + angle;
+ if ( maxArc > 360.0 )
+ {
+ // QwtRoundScaleDraw::setAngleRange accepts only values
+ // in the range [-360.0..360.0]
+ minArc -= 360.0;
+ maxArc -= 360.0;
+ }
+
+ if ( d_data->direction == QwtDial::CounterClockwise )
+ qSwap( minArc, maxArc );
+
+ painter->setFont( font() );
+
+ d_data->scaleDraw->setAngleRange( minArc, maxArc );
+ d_data->scaleDraw->setRadius( qFloor( radius ) );
+ d_data->scaleDraw->moveCenter( center );
+
+ QPalette pal = palette();
+
+ const QColor textColor = pal.color( QPalette::Text );
+ pal.setColor( QPalette::WindowText, textColor ); //ticks, backbone
+
+ painter->setPen( QPen( textColor, d_data->scaleDraw->penWidth() ) );
+
+ painter->setBrush( Qt::red );
+ d_data->scaleDraw->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 &center, double radius ) const
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(center);
+ Q_UNUSED(radius);
+}
+
+/*!
+ Set a needle for the dial
+
+ Qwt is missing a set of good looking needles.
+ Contributions are very welcome.
+
+ \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;
+}
+
+//! QwtDoubleRange update hook
+void QwtDial::rangeChange()
+{
+ updateScale();
+}
+
+/*!
+ Update the scale with the current attributes
+ \sa setScale()
+*/
+void QwtDial::updateScale()
+{
+ if ( d_data->scaleDraw )
+ {
+ QwtLinearScaleEngine scaleEngine;
+
+ const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
+ minValue(), maxValue(),
+ d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep );
+
+ d_data->scaleDraw->setTransformation( scaleEngine.transformation() );
+ d_data->scaleDraw->setScaleDiv( scaleDiv );
+ }
+}
+
+//! Return the scale draw
+QwtDialScaleDraw *QwtDial::scaleDraw()
+{
+ return d_data->scaleDraw;
+}
+
+//! Return the scale draw
+const QwtDialScaleDraw *QwtDial::scaleDraw() const
+{
+ return d_data->scaleDraw;
+}
+
+/*!
+ Set an individual scale draw
+
+ \param scaleDraw Scale draw
+ \warning The previous scale draw is deleted
+*/
+void QwtDial::setScaleDraw( QwtDialScaleDraw *scaleDraw )
+{
+ if ( scaleDraw != d_data->scaleDraw )
+ {
+ if ( d_data->scaleDraw )
+ delete d_data->scaleDraw;
+
+ d_data->scaleDraw = scaleDraw;
+ updateScale();
+ update();
+ }
+}
+
+/*!
+ Change the intervals of the scale
+
+ \param maxMajIntv Maximum for the number of major steps
+ \param maxMinIntv Maximum number of minor steps
+ \param step Step size
+
+ \sa QwtScaleEngine::divideScale()
+*/
+void QwtDial::setScale( int maxMajIntv, int maxMinIntv, double step )
+{
+ d_data->maxMajIntv = maxMajIntv;
+ d_data->maxMinIntv = maxMinIntv;
+ d_data->scaleStep = step;
+
+ updateScale();
+}
+
+/*!
+ A wrapper method for accessing the scale draw.
+
+ \param components Scale components
+ \sa QwtAbstractScaleDraw::enableComponent()
+*/
+void QwtDial::setScaleComponents(
+ QwtAbstractScaleDraw::ScaleComponents components )
+{
+ if ( components == 0 )
+ setScaleDraw( NULL );
+
+ QwtDialScaleDraw *sd = d_data->scaleDraw;
+ if ( sd == NULL )
+ return;
+
+ sd->enableComponent( QwtAbstractScaleDraw::Backbone,
+ components & QwtAbstractScaleDraw::Backbone );
+
+ sd->enableComponent( QwtAbstractScaleDraw::Ticks,
+ components & QwtAbstractScaleDraw::Ticks );
+
+ sd->enableComponent( QwtAbstractScaleDraw::Labels,
+ components & QwtAbstractScaleDraw::Labels );
+}
+
+/*!
+ Assign length and width of the ticks
+
+ \param minLen Length of the minor ticks
+ \param medLen Length of the medium ticks
+ \param majLen Length of the major ticks
+ \param penWidth Width of the pen for all ticks
+
+ \sa QwtAbstractScaleDraw::setTickLength(), QwtDialScaleDraw::setPenWidth()
+*/
+void QwtDial::setScaleTicks( int minLen, int medLen,
+ int majLen, int penWidth )
+{
+ QwtDialScaleDraw *sd = d_data->scaleDraw;
+ if ( sd )
+ {
+ sd->setTickLength( QwtScaleDiv::MinorTick, minLen );
+ sd->setTickLength( QwtScaleDiv::MediumTick, medLen );
+ sd->setTickLength( QwtScaleDiv::MajorTick, majLen );
+ sd->setPenWidth( penWidth );
+ }
+}
+
+/*!
+ Find the label for a value
+
+ \param value Value
+ \return label
+*/
+QwtText QwtDial::scaleLabel( double value ) const
+{
+ if ( value == -0.0 )
+ value = 0.0;
+
+ return QString::number( value );
+}
+
+//! \return Lower limit of the scale arc
+double QwtDial::minScaleArc() const
+{
+ return d_data->minScaleArc;
+}
+
+//! \return Upper limit of the scale arc
+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 )
+{
+ d_data->origin = origin;
+ update();
+}
+
+/*!
+ 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;
+}
+
+/*!
+ Change the arc of the scale
+
+ \param minArc Lower limit
+ \param maxArc Upper limit
+*/
+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 );
+
+ d_data->minScaleArc = qMin( minArc, maxArc );
+ d_data->maxScaleArc = qMax( minArc, maxArc );
+ if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
+ d_data->maxScaleArc = d_data->minScaleArc + 360.0;
+
+ update();
+}
+
+//! QwtDoubleRange update hook
+void QwtDial::valueChange()
+{
+ update();
+ QwtAbstractSlider::valueChange();
+}
+
+/*!
+ \return Size hint
+*/
+QSize QwtDial::sizeHint() const
+{
+ int sh = 0;
+ if ( d_data->scaleDraw )
+ sh = qCeil( d_data->scaleDraw->extent( font() ) );
+
+ const int d = 6 * sh + 2 * lineWidth();
+
+ QSize hint( d, d );
+ if ( !isReadOnly() )
+ hint = hint.expandedTo( QApplication::globalStrut() );
+
+ return hint;
+}
+
+/*!
+ \brief Return a minimum size hint
+ \warning The return value of QwtDial::minimumSizeHint() depends on the
+ font and the scale.
+*/
+QSize QwtDial::minimumSizeHint() const
+{
+ int sh = 0;
+ if ( d_data->scaleDraw )
+ sh = qCeil( d_data->scaleDraw->extent( font() ) );
+
+ const int d = 3 * sh + 2 * lineWidth();
+
+ return QSize( d, d );
+}
+
+static double line2Degrees( const QPointF &p1, const QPointF &p2 )
+{
+ const QPointF p = p2 - p1;
+
+ double angle;
+ if ( p.x() == 0.0 )
+ {
+ angle = ( p.y() <= 0.0 ) ? M_PI_2 : 3 * M_PI_2;
+ }
+ else
+ {
+ angle = qAtan( double( -p.y() ) / double( p.x() ) );
+ if ( p.x() < 0.0 )
+ angle += M_PI;
+ if ( angle < 0.0 )
+ angle += 2 * M_PI;
+ }
+ return 360.0 - angle * 180.0 / M_PI;
+}
+
+/*!
+ Find the value for a given position
+
+ \param pos Position
+ \return Value
+*/
+double QwtDial::getValue( const QPoint &pos )
+{
+ if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
+ return minValue();
+
+ double dir = line2Degrees( innerRect().center(), pos ) - d_data->origin;
+ if ( dir < 0.0 )
+ dir += 360.0;
+
+ if ( mode() == RotateScale )
+ dir = 360.0 - dir;
+
+ // The position might be in the area that is outside the scale arc.
+ // We need the range of the scale if it was a complete circle.
+
+ const double completeCircle = 360.0 / ( d_data->maxScaleArc - d_data->minScaleArc )
+ * ( maxValue() - minValue() );
+
+ double posValue = minValue() + completeCircle * dir / 360.0;
+
+ if ( scrollMode() == ScrMouse )
+ {
+ if ( d_data->previousDir >= 0.0 ) // valid direction
+ {
+ // We have to find out whether the mouse is moving
+ // clock or counter clockwise
+
+ bool clockWise = false;
+
+ const double angle = dir - d_data->previousDir;
+ if ( ( angle >= 0.0 && angle <= 180.0 ) || angle < -180.0 )
+ clockWise = true;
+
+ if ( clockWise )
+ {
+ if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
+ {
+ // We passed 360 -> 0
+ setMouseOffset( mouseOffset() - completeCircle );
+ }
+
+ if ( wrapping() )
+ {
+ if ( posValue - mouseOffset() > maxValue() )
+ {
+ // We passed maxValue and the value will be set
+ // to minValue. We have to adjust the mouseOffset.
+
+ setMouseOffset( posValue - minValue() );
+ }
+ }
+ else
+ {
+ if ( posValue - mouseOffset() > maxValue() ||
+ value() == maxValue() )
+ {
+ // We fix the value at maxValue by adjusting
+ // the mouse offset.
+
+ setMouseOffset( posValue - maxValue() );
+ }
+ }
+ }
+ else
+ {
+ if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
+ {
+ // We passed 0 -> 360
+ setMouseOffset( mouseOffset() + completeCircle );
+ }
+
+ if ( wrapping() )
+ {
+ if ( posValue - mouseOffset() < minValue() )
+ {
+ // We passed minValue and the value will be set
+ // to maxValue. We have to adjust the mouseOffset.
+
+ setMouseOffset( posValue - maxValue() );
+ }
+ }
+ else
+ {
+ if ( posValue - mouseOffset() < minValue() ||
+ value() == minValue() )
+ {
+ // We fix the value at minValue by adjusting
+ // the mouse offset.
+
+ setMouseOffset( posValue - minValue() );
+ }
+ }
+ }
+ }
+ d_data->previousDir = dir;
+ }
+
+ return posValue;
+}
+
+/*!
+ See QwtAbstractSlider::getScrollMode()
+
+ \param pos point where the mouse was pressed
+ \retval scrollMode The scrolling mode
+ \retval direction direction: 1, 0, or -1.
+
+ \sa QwtAbstractSlider::getScrollMode()
+*/
+void QwtDial::getScrollMode( const QPoint &pos,
+ QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const
+{
+ direction = 0;
+ scrollMode = QwtAbstractSlider::ScrNone;
+
+ const QRegion region( innerRect().toRect(), QRegion::Ellipse );
+ if ( region.contains( pos ) && pos != innerRect().center() )
+ {
+ scrollMode = QwtAbstractSlider::ScrMouse;
+ d_data->previousDir = -1.0;
+ }
+}
+
+/*!
+ Handles key events
+
+ - Key_Down, KeyLeft\n
+ Decrement by 1
+ - Key_Prior\n
+ Decrement by pageSize()
+ - Key_Home\n
+ Set the value to minValue()
+
+ - Key_Up, KeyRight\n
+ Increment by 1
+ - Key_Next\n
+ Increment by pageSize()
+ - Key_End\n
+ Set the value to maxValue()
+
+ \param event Key event
+ \sa isReadOnly()
+*/
+void QwtDial::keyPressEvent( QKeyEvent *event )
+{
+ if ( isReadOnly() )
+ {
+ event->ignore();
+ return;
+ }
+
+ if ( !isValid() )
+ return;
+
+ const double previousValue = value();
+
+ switch ( event->key() )
+ {
+ case Qt::Key_Down:
+ case Qt::Key_Left:
+ QwtDoubleRange::incValue( -1 );
+ break;
+ case Qt::Key_PageUp:
+ QwtDoubleRange::incValue( -pageSize() );
+ break;
+ case Qt::Key_Home:
+ setValue( minValue() );
+ break;
+
+ case Qt::Key_Up:
+ case Qt::Key_Right:
+ QwtDoubleRange::incValue( 1 );
+ break;
+ case Qt::Key_PageDown:
+ QwtDoubleRange::incValue( pageSize() );
+ break;
+ case Qt::Key_End:
+ setValue( maxValue() );
+ break;
+ default:;
+ event->ignore();
+ }
+
+ if ( value() != previousValue )
+ Q_EMIT sliderMoved( value() );
+}
diff --git a/src/libpcp_qwt/src/qwt_dial.h b/src/libpcp_qwt/src/qwt_dial.h
new file mode 100644
index 0000000..128ceda
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dial.h
@@ -0,0 +1,215 @@
+/* -*- 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_round_scale_draw.h"
+#include <qframe.h>
+#include <qpalette.h>
+
+class QwtDialNeedle;
+class QwtDial;
+
+/*!
+ \brief A special scale draw made for QwtDial
+
+ \sa QwtDial, QwtCompass
+*/
+class QWT_EXPORT QwtDialScaleDraw: public QwtRoundScaleDraw
+{
+public:
+ explicit QwtDialScaleDraw( QwtDial * );
+
+ virtual QwtText label( double value ) const;
+
+ void setPenWidth( double );
+ double penWidth() const;
+
+private:
+ QwtDial *d_parent;
+ double d_penWidth;
+};
+
+/*!
+ \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 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.
+
+ Qwt is missing a set of good looking needles (QwtDialNeedle).
+ Contributions are very welcome.
+
+ \sa QwtCompass, QwtAnalogClock, QwtDialNeedle
+ \note The examples/dials example shows different types of dials.
+*/
+
+class QWT_EXPORT QwtDial: public QwtAbstractSlider
+{
+ Q_OBJECT
+
+ Q_ENUMS( Shadow )
+ Q_ENUMS( Mode )
+ Q_ENUMS( 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( bool wrapping READ wrapping WRITE setWrapping )
+ Q_PROPERTY( Direction direction READ direction WRITE setDirection )
+
+ friend class QwtDialScaleDraw;
+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 wether the needle or the scale is rotating
+ enum Mode
+ {
+ //! The needle is rotating
+ RotateNeedle,
+
+ //! The needle is fixed, the scales are rotating
+ RotateScale
+ };
+
+ //! Direction of the dial
+ enum Direction
+ {
+ //! Clockwise
+ Clockwise,
+
+ //! Counter clockwise
+ CounterClockwise
+ };
+
+ 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;
+
+ virtual void setWrapping( bool );
+ bool wrapping() const;
+
+ virtual void setScale( int maxMajIntv, int maxMinIntv, double step = 0.0 );
+
+ void setScaleArc( double min, double max );
+ void setScaleComponents( QwtAbstractScaleDraw::ScaleComponents );
+ void setScaleTicks( int minLen, int medLen, int majLen, int penWidth = 1 );
+
+ double minScaleArc() const;
+ double maxScaleArc() const;
+
+ virtual void setOrigin( double );
+ double origin() const;
+
+ void setDirection( Direction );
+ Direction direction() const;
+
+ virtual void setNeedle( QwtDialNeedle * );
+ const QwtDialNeedle *needle() const;
+ QwtDialNeedle *needle();
+
+ QRectF boundingRect() const;
+ QRectF innerRect() const;
+ virtual QRectF scaleInnerRect() const;
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ virtual void setScaleDraw( QwtDialScaleDraw * );
+
+ QwtDialScaleDraw *scaleDraw();
+ const QwtDialScaleDraw *scaleDraw() const;
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void keyPressEvent( QKeyEvent * );
+
+ virtual void drawFrame( QPainter *p );
+ virtual void drawContents( QPainter * ) const;
+ virtual void drawFocusIndicator( QPainter * ) const;
+
+ virtual void drawScale(
+ QPainter *, const QPointF &center,
+ double radius, double origin,
+ double arcMin, double arcMax ) const;
+
+ /*!
+ 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
+ */
+ virtual void drawScaleContents( QPainter *painter,
+ const QPointF &center, double radius ) const;
+
+ virtual void drawNeedle( QPainter *, const QPointF &,
+ double radius, double direction, QPalette::ColorGroup ) const;
+
+ virtual QwtText scaleLabel( double ) const;
+ void updateScale();
+
+ virtual void rangeChange();
+ virtual void valueChange();
+
+ virtual double getValue( const QPoint & );
+ virtual void getScrollMode( const QPoint &,
+ QwtAbstractSlider::ScrollMode &, int &direction ) const;
+
+private:
+ void initDial();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_dial_needle.cpp b/src/libpcp_qwt/src/qwt_dial_needle.cpp
new file mode 100644
index 0000000..3888c11
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dial_needle.cpp
@@ -0,0 +1,441 @@
+/* -*- 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_needle.h"
+#include "qwt_global.h"
+#include "qwt_math.h"
+#include "qwt_painter.h"
+#include <qapplication.h>
+#include <qpainter.h>
+
+#if QT_VERSION < 0x040601
+#define qFastSin(x) qSin(x)
+#define qFastCos(x) qCos(x)
+#endif
+
+static void qwtDrawStyle1Needle( QPainter *painter,
+ const QPalette &palette, QPalette::ColorGroup colorGroup,
+ double length )
+{
+ const double r[] = { 0.4, 0.3, 1, 0.8, 1, 0.3, 0.4 };
+ const double a[] = { -45, -20, -15, 0, 15, 20, 45 };
+
+ QPainterPath path;
+ for ( int i = 0; i < 7; i++ )
+ {
+ const double angle = a[i] / 180.0 * M_PI;
+ const double radius = r[i] * length;
+
+ const double x = radius * qFastCos( angle );
+ const double y = radius * qFastSin( angle );
+
+ path.lineTo( x, -y );
+ }
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
+ painter->drawPath( path );
+}
+
+static void qwtDrawStyle2Needle( QPainter *painter,
+ const QPalette &palette, QPalette::ColorGroup colorGroup, double length )
+{
+ const double ratioX = 0.7;
+ const double ratioY = 0.3;
+
+ QPainterPath path1;
+ path1.lineTo( ratioX * length, 0.0 );
+ path1.lineTo( length, ratioY * length );
+
+ QPainterPath path2;
+ path2.lineTo( ratioX * length, 0.0 );
+ path2.lineTo( length, -ratioY * length );
+
+ painter->setPen( Qt::NoPen );
+
+ painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
+ painter->drawPath( path1 );
+
+ painter->setBrush( palette.brush( colorGroup, QPalette::Dark ) );
+ painter->drawPath( path2 );
+}
+
+static void qwtDrawShadedPointer( QPainter *painter,
+ const QColor &lightColor, const QColor &darkColor,
+ double length, double width )
+{
+ const double peak = qMax( length / 10.0, 5.0 );
+
+ const double knobWidth = width + 8;
+ QRectF knobRect( 0, 0, knobWidth, knobWidth );
+ knobRect.moveCenter( QPointF(0, 0) );
+
+ QPainterPath path1;
+ path1.lineTo( 0.0, 0.5 * width );
+ path1.lineTo( length - peak, 0.5 * width );
+ path1.lineTo( length, 0.0 );
+ path1.lineTo( 0.0, 0.0 );
+
+ QPainterPath arcPath1;
+ arcPath1.arcTo( knobRect, 0.0, -90.0 );
+
+ path1 = path1.united( arcPath1 );
+
+ QPainterPath path2;
+ path2.lineTo( 0.0, -0.5 * width );
+ path2.lineTo( length - peak, -0.5 * width );
+ path2.lineTo( length, 0.0 );
+ path2.lineTo( 0.0, 0.0 );
+
+ QPainterPath arcPath2;
+ arcPath2.arcTo( knobRect, 0.0, 90.0 );
+
+ path2 = path2.united( arcPath2 );
+
+ painter->setPen( Qt::NoPen );
+
+ painter->setBrush( lightColor );
+ painter->drawPath( path1 );
+
+ painter->setBrush( darkColor );
+ painter->drawPath( path2 );
+}
+
+static void qwtDrawArrowNeedle( QPainter *painter,
+ const QPalette &palette, QPalette::ColorGroup colorGroup,
+ double length, double width )
+{
+ if ( width <= 0 )
+ width = qMax( length * 0.06, 9.0 );
+
+ const double peak = qMax( 2.0, 0.4 * width );
+
+ QPainterPath path;
+ path.moveTo( 0.0, 0.5 * width );
+ path.lineTo( length - peak, 0.3 * width );
+ path.lineTo( length, 0.0 );
+ path.lineTo( length - peak, -0.3 * width );
+ path.lineTo( 0.0, -0.5 * width );
+
+ QRectF br = path.boundingRect();
+
+ QPalette pal( palette.color( QPalette::Mid ) );
+ QColor c1 = pal.color( QPalette::Light );
+ QColor c2 = pal.color( QPalette::Dark );
+
+ QLinearGradient gradient( br.topLeft(), br.bottomLeft() );
+ gradient.setColorAt( 0.0, c1 );
+ gradient.setColorAt( 0.5, c1 );
+ gradient.setColorAt( 0.5001, c2 );
+ gradient.setColorAt( 1.0, c2 );
+
+ QPen pen( gradient, 1 );
+ pen.setJoinStyle( Qt::MiterJoin );
+
+ painter->setPen( pen );
+ painter->setBrush( palette.brush( colorGroup, QPalette::Mid ) );
+
+ painter->drawPath( path );
+}
+
+static void qwtDrawTriangleNeedle( QPainter *painter,
+ const QPalette &palette, QPalette::ColorGroup colorGroup,
+ double length )
+{
+ const double width = qRound( length / 3.0 );
+
+ QPainterPath path[4];
+
+ path[0].lineTo( length, 0.0 );
+ path[0].lineTo( 0.0, width / 2 );
+
+ path[1].lineTo( length, 0.0 );
+ path[1].lineTo( 0.0, -width / 2 );
+
+ path[2].lineTo( -length, 0.0 );
+ path[2].lineTo( 0.0, width / 2 );
+
+ path[3].lineTo( -length, 0.0 );
+ path[3].lineTo( 0.0, -width / 2 );
+
+
+ const int colorOffset = 10;
+ const QColor darkColor = palette.color( colorGroup, QPalette::Dark );
+ const QColor lightColor = palette.color( colorGroup, QPalette::Light );
+
+ QColor color[4];
+ color[0] = darkColor.light( 100 + colorOffset );
+ color[1] = darkColor.dark( 100 + colorOffset );
+ color[2] = lightColor.light( 100 + colorOffset );
+ color[3] = lightColor.dark( 100 + colorOffset );
+
+ painter->setPen( Qt::NoPen );
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ painter->setBrush( color[i] );
+ painter->drawPath( path[i] );
+ }
+}
+
+//! Constructor
+QwtDialNeedle::QwtDialNeedle():
+ d_palette( QApplication::palette() )
+{
+}
+
+//! Destructor
+QwtDialNeedle::~QwtDialNeedle()
+{
+}
+
+/*!
+ Sets the palette for the needle.
+
+ \param palette New Palette
+*/
+void QwtDialNeedle::setPalette( const QPalette &palette )
+{
+ d_palette = palette;
+}
+
+/*!
+ \return the palette of the needle.
+*/
+const QPalette &QwtDialNeedle::palette() const
+{
+ return d_palette;
+}
+
+/*!
+ Draw the needle
+
+ \param painter Painter
+ \param center Center of the dial, start position for the needle
+ \param length Length of the needle
+ \param direction Direction of the needle, in degrees counter clockwise
+ \param colorGroup Color group, used for painting
+*/
+void QwtDialNeedle::draw( QPainter *painter,
+ const QPointF &center, double length, double direction,
+ QPalette::ColorGroup colorGroup ) const
+{
+ painter->save();
+
+ painter->translate( center );
+ painter->rotate( -direction );
+
+ drawNeedle( painter, length, colorGroup );
+
+ painter->restore();
+}
+
+//! Draw the knob
+void QwtDialNeedle::drawKnob( QPainter *painter,
+ double width, const QBrush &brush, bool sunken ) const
+{
+ QPalette palette( brush.color() );
+
+ QColor c1 = palette.color( QPalette::Light );
+ QColor c2 = palette.color( QPalette::Dark );
+
+ if ( sunken )
+ qSwap( c1, c2 );
+
+ QRectF rect( 0.0, 0.0, width, width );
+ rect.moveCenter( painter->combinedTransform().map( QPointF() ) );
+
+ QLinearGradient gradient( rect.topLeft(), rect.bottomRight() );
+ gradient.setColorAt( 0.0, c1 );
+ gradient.setColorAt( 0.3, c1 );
+ gradient.setColorAt( 0.7, c2 );
+ gradient.setColorAt( 1.0, c2 );
+
+ painter->save();
+
+ painter->resetTransform();
+
+ painter->setPen( QPen( gradient, 1 ) );
+ painter->setBrush( brush );
+ painter->drawEllipse( rect );
+
+ painter->restore();
+}
+
+/*!
+ Constructor
+
+ \param style Style
+ \param hasKnob With/Without knob
+ \param mid Middle color
+ \param base Base color
+*/
+QwtDialSimpleNeedle::QwtDialSimpleNeedle( Style style, bool hasKnob,
+ const QColor &mid, const QColor &base ):
+ d_style( style ),
+ d_hasKnob( hasKnob ),
+ d_width( -1 )
+{
+ QPalette palette;
+ palette.setColor( QPalette::Mid, mid );
+ palette.setColor( QPalette::Base, base );
+
+ setPalette( palette );
+}
+
+/*!
+ Set the width of the needle
+ \param width Width
+ \sa width()
+*/
+void QwtDialSimpleNeedle::setWidth( double width )
+{
+ d_width = width;
+}
+
+/*!
+ \return the width of the needle
+ \sa setWidth()
+*/
+double QwtDialSimpleNeedle::width() const
+{
+ return d_width;
+}
+
+/*!
+ Draw the needle
+
+ \param painter Painter
+ \param length Length of the needle
+ \param colorGroup Color group, used for painting
+*/
+void QwtDialSimpleNeedle::drawNeedle( QPainter *painter,
+ double length, QPalette::ColorGroup colorGroup ) const
+{
+ double knobWidth = 0.0;
+ double width = d_width;
+
+ if ( d_style == Arrow )
+ {
+ if ( width <= 0.0 )
+ width = qMax(length * 0.06, 6.0);
+
+ qwtDrawArrowNeedle( painter,
+ palette(), colorGroup, length, width );
+
+ knobWidth = qMin( width * 2.0, 0.2 * length );
+ }
+ else
+ {
+ if ( width <= 0.0 )
+ width = 5.0;
+
+ QPen pen ( palette().brush( colorGroup, QPalette::Mid ), width );
+ pen.setCapStyle( Qt::FlatCap );
+
+ painter->setPen( pen );
+ painter->drawLine( QPointF( 0.0, 0.0 ), QPointF( length, 0.0 ) );
+
+ knobWidth = qMax( width * 3.0, 5.0 );
+ }
+
+ if ( d_hasKnob && knobWidth > 0.0 )
+ {
+ drawKnob( painter, knobWidth,
+ palette().brush( colorGroup, QPalette::Base ), false );
+ }
+}
+
+//! Constructor
+
+QwtCompassMagnetNeedle::QwtCompassMagnetNeedle( Style style,
+ const QColor &light, const QColor &dark ):
+ d_style( style )
+{
+ QPalette palette;
+ palette.setColor( QPalette::Light, light );
+ palette.setColor( QPalette::Dark, dark );
+ palette.setColor( QPalette::Base, Qt::gray );
+
+ setPalette( palette );
+}
+
+/*!
+ Draw the needle
+
+ \param painter Painter
+ \param length Length of the needle
+ \param colorGroup Color group, used for painting
+*/
+void QwtCompassMagnetNeedle::drawNeedle( QPainter *painter,
+ double length, QPalette::ColorGroup colorGroup ) const
+{
+ if ( d_style == ThinStyle )
+ {
+ const double width = qMax( length / 6.0, 3.0 );
+
+ const int colorOffset = 10;
+
+ const QColor light = palette().color( colorGroup, QPalette::Light );
+ const QColor dark = palette().color( colorGroup, QPalette::Dark );
+
+ qwtDrawShadedPointer( painter,
+ dark.light( 100 + colorOffset ),
+ dark.dark( 100 + colorOffset ),
+ length, width );
+
+ painter->rotate( 180.0 );
+
+ qwtDrawShadedPointer( painter,
+ light.light( 100 + colorOffset ),
+ light.dark( 100 + colorOffset ),
+ length, width );
+
+ const QBrush baseBrush = palette().brush( colorGroup, QPalette::Base );
+ drawKnob( painter, width, baseBrush, true );
+ }
+ else
+ {
+ qwtDrawTriangleNeedle( painter, palette(), colorGroup, length );
+ }
+}
+
+/*!
+ Constructor
+
+ \param style Arrow style
+ \param light Light color
+ \param dark Dark color
+*/
+QwtCompassWindArrow::QwtCompassWindArrow( Style style,
+ const QColor &light, const QColor &dark ):
+ d_style( style )
+{
+ QPalette palette;
+ palette.setColor( QPalette::Light, light );
+ palette.setColor( QPalette::Dark, dark );
+
+ setPalette( palette );
+}
+
+/*!
+ Draw the needle
+
+ \param painter Painter
+ \param length Length of the needle
+ \param colorGroup Color group, used for painting
+*/
+void QwtCompassWindArrow::drawNeedle( QPainter *painter,
+ double length, QPalette::ColorGroup colorGroup ) const
+{
+ if ( d_style == Style1 )
+ qwtDrawStyle1Needle( painter, palette(), colorGroup, length );
+ else
+ qwtDrawStyle2Needle( painter, palette(), colorGroup, length );
+}
diff --git a/src/libpcp_qwt/src/qwt_dial_needle.h b/src/libpcp_qwt/src/qwt_dial_needle.h
new file mode 100644
index 0000000..a02a590
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dial_needle.h
@@ -0,0 +1,190 @@
+/* -*- 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.
+
+ Qwt is missing a set of good looking needles.
+ Contributions are very welcome.
+
+ \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 &center,
+ 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 initilaized 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
diff --git a/src/libpcp_qwt/src/qwt_double_range.cpp b/src/libpcp_qwt/src/qwt_double_range.cpp
new file mode 100644
index 0000000..b073eab
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_double_range.cpp
@@ -0,0 +1,410 @@
+/* -*- 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_double_range.h"
+#include "qwt_math.h"
+
+#if QT_VERSION < 0x040601
+#define qFabs(x) ::fabs(x)
+#endif
+
+class QwtDoubleRange::PrivateData
+{
+public:
+ PrivateData():
+ minValue( 0.0 ),
+ maxValue( 0.0 ),
+ step( 1.0 ),
+ pageSize( 1 ),
+ isValid( false ),
+ value( 0.0 ),
+ exactValue( 0.0 ),
+ exactPrevValue( 0.0 ),
+ prevValue( 0.0 ),
+ periodic( false )
+ {
+ }
+
+ double minValue;
+ double maxValue;
+ double step;
+ int pageSize;
+
+ bool isValid;
+ double value;
+ double exactValue;
+ double exactPrevValue;
+ double prevValue;
+
+ bool periodic;
+};
+
+/*!
+ The range is initialized to [0.0, 100.0], the
+ step size to 1.0, and the value to 0.0.
+*/
+QwtDoubleRange::QwtDoubleRange()
+{
+ d_data = new PrivateData();
+}
+
+//! Destroys the QwtDoubleRange
+QwtDoubleRange::~QwtDoubleRange()
+{
+ delete d_data;
+}
+
+//! Set the value to be valid/invalid
+void QwtDoubleRange::setValid( bool isValid )
+{
+ if ( isValid != d_data->isValid )
+ {
+ d_data->isValid = isValid;
+ valueChange();
+ }
+}
+
+//! Indicates if the value is valid
+bool QwtDoubleRange::isValid() const
+{
+ return d_data->isValid;
+}
+
+void QwtDoubleRange::setNewValue( double value, bool align )
+{
+ d_data->prevValue = d_data->value;
+
+ const double vmin = qMin( d_data->minValue, d_data->maxValue );
+ const double vmax = qMax( d_data->minValue, d_data->maxValue );
+
+ if ( value < vmin )
+ {
+ if ( d_data->periodic && vmin != vmax )
+ {
+ d_data->value = value +
+ ::ceil( ( vmin - value ) / ( vmax - vmin ) ) * ( vmax - vmin );
+ }
+ else
+ d_data->value = vmin;
+ }
+ else if ( value > vmax )
+ {
+ if ( ( d_data->periodic ) && ( vmin != vmax ) )
+ {
+ d_data->value = value -
+ ::ceil( ( value - vmax ) / ( vmax - vmin ) ) * ( vmax - vmin );
+ }
+ else
+ d_data->value = vmax;
+ }
+ else
+ {
+ d_data->value = value;
+ }
+
+ d_data->exactPrevValue = d_data->exactValue;
+ d_data->exactValue = d_data->value;
+
+ if ( align )
+ {
+ if ( d_data->step != 0.0 )
+ {
+ d_data->value = d_data->minValue +
+ qRound( ( d_data->value - d_data->minValue ) / d_data->step ) * d_data->step;
+ }
+ else
+ d_data->value = d_data->minValue;
+
+ const double minEps = 1.0e-10;
+ // correct rounding error at the border
+ if ( qFabs( d_data->value - d_data->maxValue ) < minEps * qAbs( d_data->step ) )
+ d_data->value = d_data->maxValue;
+
+ // correct rounding error if value = 0
+ if ( qFabs( d_data->value ) < minEps * qAbs( d_data->step ) )
+ d_data->value = 0.0;
+ }
+
+ if ( !d_data->isValid || d_data->prevValue != d_data->value )
+ {
+ d_data->isValid = true;
+ valueChange();
+ }
+}
+
+/*!
+ \brief Adjust the value to the closest point in the step raster.
+ \param x value
+ \warning The value is clipped when it lies outside the range.
+ When the range is QwtDoubleRange::periodic, it will
+ be mapped to a point in the interval such that
+ \verbatim new value := x + n * (max. value - min. value)\endverbatim
+ with an integer number n.
+*/
+void QwtDoubleRange::fitValue( double x )
+{
+ setNewValue( x, true );
+}
+
+
+/*!
+ \brief Set a new value without adjusting to the step raster
+ \param x new value
+ \warning The value is clipped when it lies outside the range.
+ When the range is QwtDoubleRange::periodic, it will
+ be mapped to a point in the interval such that
+ \verbatim new value := x + n * (max. value - min. value)\endverbatim
+ with an integer number n.
+*/
+void QwtDoubleRange::setValue( double x )
+{
+ setNewValue( x, false );
+}
+
+/*!
+ \brief Specify range and step size
+
+ \param vmin lower boundary of the interval
+ \param vmax higher boundary of the interval
+ \param vstep step width
+ \param pageSize page size in steps
+ \warning
+ \li A change of the range changes the value if it lies outside the
+ new range. The current value
+ will *not* be adjusted to the new step raster.
+ \li vmax < vmin is allowed.
+ \li If the step size is left out or set to zero, it will be
+ set to 1/100 of the interval length.
+ \li If the step size has an absurd value, it will be corrected
+ to a better one.
+*/
+void QwtDoubleRange::setRange(
+ double vmin, double vmax, double vstep, int pageSize )
+{
+ const bool rchg = ( d_data->maxValue != vmax || d_data->minValue != vmin );
+
+ if ( rchg )
+ {
+ d_data->minValue = vmin;
+ d_data->maxValue = vmax;
+ }
+
+ // look if the step width has an acceptable
+ // value or otherwise change it.
+ setStep( vstep );
+
+ // limit page size
+ const int max =
+ int( qAbs( ( d_data->maxValue - d_data->minValue ) / d_data->step ) );
+ d_data->pageSize = qBound( 0, pageSize, max );
+
+ // If the value lies out of the range, it
+ // will be changed. Note that it will not be adjusted to
+ // the new step width.
+ setNewValue( d_data->value, false );
+
+ // call notifier after the step width has been
+ // adjusted.
+ if ( rchg )
+ rangeChange();
+}
+
+/*!
+ \brief Change the step raster
+ \param vstep new step width
+ \warning The value will \e not be adjusted to the new step raster.
+*/
+void QwtDoubleRange::setStep( double vstep )
+{
+ const double intv = d_data->maxValue - d_data->minValue;
+
+ double newStep;
+ if ( vstep == 0.0 )
+ {
+ const double defaultRelStep = 1.0e-2;
+ newStep = intv * defaultRelStep;
+ }
+ else
+ {
+ if ( ( intv > 0.0 && vstep < 0.0 ) || ( intv < 0.0 && vstep > 0.0 ) )
+ newStep = -vstep;
+ else
+ newStep = vstep;
+
+ const double minRelStep = 1.0e-10;
+ if ( qFabs( newStep ) < qFabs( minRelStep * intv ) )
+ newStep = minRelStep * intv;
+ }
+
+ if ( newStep != d_data->step )
+ {
+ d_data->step = newStep;
+ stepChange();
+ }
+}
+
+
+/*!
+ \brief Make the range periodic
+
+ When the range is periodic, the value will be set to a point
+ inside the interval such that
+
+ \verbatim point = value + n * width \endverbatim
+
+ if the user tries to set a new value which is outside the range.
+ If the range is nonperiodic (the default), values outside the
+ range will be clipped.
+
+ \param tf true for a periodic range
+*/
+void QwtDoubleRange::setPeriodic( bool tf )
+{
+ d_data->periodic = tf;
+}
+
+/*!
+ \brief Increment the value by a specified number of steps
+ \param nSteps Number of steps to increment
+ \warning As a result of this operation, the new value will always be
+ adjusted to the step raster.
+*/
+void QwtDoubleRange::incValue( int nSteps )
+{
+ if ( isValid() )
+ setNewValue( d_data->value + double( nSteps ) * d_data->step, true );
+}
+
+/*!
+ \brief Increment the value by a specified number of pages
+ \param nPages Number of pages to increment.
+ A negative number decrements the value.
+ \warning The Page size is specified in the constructor.
+*/
+void QwtDoubleRange::incPages( int nPages )
+{
+ if ( isValid() )
+ {
+ const double off = d_data->step * d_data->pageSize * nPages;
+ setNewValue( d_data->value + off, true );
+ }
+}
+
+/*!
+ \brief Notify a change of value
+
+ This virtual function is called whenever the value changes.
+ The default implementation does nothing.
+*/
+void QwtDoubleRange::valueChange()
+{
+}
+
+
+/*!
+ \brief Notify a change of the range
+
+ This virtual function is called whenever the range changes.
+ The default implementation does nothing.
+*/
+void QwtDoubleRange::rangeChange()
+{
+}
+
+
+/*!
+ \brief Notify a change of the step size
+
+ This virtual function is called whenever the step size changes.
+ The default implementation does nothing.
+*/
+void QwtDoubleRange::stepChange()
+{
+}
+
+/*!
+ \return the step size
+ \sa setStep(), setRange()
+*/
+double QwtDoubleRange::step() const
+{
+ return qAbs( d_data->step );
+}
+
+/*!
+ \brief Returns the value of the second border of the range
+
+ maxValue returns the value which has been specified
+ as the second parameter in QwtDoubleRange::setRange.
+
+ \sa setRange()
+*/
+double QwtDoubleRange::maxValue() const
+{
+ return d_data->maxValue;
+}
+
+/*!
+ \brief Returns the value at the first border of the range
+
+ minValue returns the value which has been specified
+ as the first parameter in setRange().
+
+ \sa setRange()
+*/
+double QwtDoubleRange::minValue() const
+{
+ return d_data->minValue;
+}
+
+/*!
+ \brief Returns true if the range is periodic
+ \sa setPeriodic()
+*/
+bool QwtDoubleRange::periodic() const
+{
+ return d_data->periodic;
+}
+
+//! Returns the page size in steps.
+int QwtDoubleRange::pageSize() const
+{
+ return d_data->pageSize;
+}
+
+//! Returns the current value.
+double QwtDoubleRange::value() const
+{
+ return d_data->value;
+}
+
+/*!
+ \brief Returns the exact value
+
+ The exact value is the value which QwtDoubleRange::value would return
+ if the value were not adjusted to the step raster. It differs from
+ the current value only if fitValue() or incValue() have been used before.
+ This function is intended for internal use in derived classes.
+*/
+double QwtDoubleRange::exactValue() const
+{
+ return d_data->exactValue;
+}
+
+//! Returns the exact previous value
+double QwtDoubleRange::exactPrevValue() const
+{
+ return d_data->exactPrevValue;
+}
+
+//! Returns the previous value
+double QwtDoubleRange::prevValue() const
+{
+ return d_data->prevValue;
+}
diff --git a/src/libpcp_qwt/src/qwt_double_range.h b/src/libpcp_qwt/src/qwt_double_range.h
new file mode 100644
index 0000000..29f2f66
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_double_range.h
@@ -0,0 +1,78 @@
+/* -*- 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_DOUBLE_RANGE_H
+#define QWT_DOUBLE_RANGE_H
+
+#include "qwt_global.h"
+
+/*!
+ \brief A class which controls a value within an interval
+
+ This class is useful as a base class or a member for sliders.
+ It represents an interval of type double within which a value can
+ be moved. The value can be either an arbitrary point inside
+ the interval (see QwtDoubleRange::setValue), or it can be fitted
+ into a step raster (see QwtDoubleRange::fitValue and
+ QwtDoubleRange::incValue).
+
+ As a special case, a QwtDoubleRange can be periodic, which means that
+ a value outside the interval will be mapped to a value inside the
+ interval when QwtDoubleRange::setValue(), QwtDoubleRange::fitValue(),
+ QwtDoubleRange::incValue() or QwtDoubleRange::incPages() are called.
+*/
+
+class QWT_EXPORT QwtDoubleRange
+{
+public:
+ QwtDoubleRange();
+ virtual ~QwtDoubleRange();
+
+ void setRange( double vmin, double vmax,
+ double vstep = 0.0, int pagesize = 1 );
+
+ void setValid( bool );
+ bool isValid() const;
+
+ virtual void setValue( double );
+ double value() const;
+
+ void setPeriodic( bool tf );
+ bool periodic() const;
+
+ void setStep( double );
+ double step() const;
+
+ double maxValue() const;
+ double minValue() const;
+
+ int pageSize() const;
+
+ virtual void incValue( int );
+ virtual void incPages( int );
+ virtual void fitValue( double );
+
+protected:
+
+ double exactValue() const;
+ double exactPrevValue() const;
+ double prevValue() const;
+
+ virtual void valueChange();
+ virtual void stepChange();
+ virtual void rangeChange();
+
+private:
+ void setNewValue( double value, bool align = false );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_dyngrid_layout.cpp b/src/libpcp_qwt/src/qwt_dyngrid_layout.cpp
new file mode 100644
index 0000000..e6968ae
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dyngrid_layout.cpp
@@ -0,0 +1,575 @@
+/* -*- 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 maxCols;
+ uint numRows;
+ uint numCols;
+
+ 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->maxCols = d_data->numRows = d_data->numCols = 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 maxCols upper limit, 0 means unlimited
+ \sa maxCols()
+*/
+void QwtDynGridLayout::setMaxCols( uint maxCols )
+{
+ d_data->maxCols = maxCols;
+}
+
+/*!
+ Return the upper limit for the number of columns.
+ 0 means unlimited, what is the default.
+ \sa setMaxCols()
+*/
+
+uint QwtDynGridLayout::maxCols() const
+{
+ return d_data->maxCols;
+}
+
+//! Adds item to the next free position.
+
+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 spcific index
+
+ \param index 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 spcific index and remove it from the layout
+
+ \param index Index
+ \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;
+}
+
+/*!
+ 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.
+ \sa setExpandingDirections()
+*/
+Qt::Orientations QwtDynGridLayout::expandingDirections() const
+{
+ return d_data->expanding;
+}
+
+/*!
+ Reorganizes columns and rows and resizes managed items within
+ the rectangle rect.
+
+ \param rect Layout geometry
+*/
+void QwtDynGridLayout::setGeometry( const QRect &rect )
+{
+ QLayout::setGeometry( rect );
+
+ if ( isEmpty() )
+ return;
+
+ d_data->numCols = columnsForWidth( rect.width() );
+ d_data->numRows = itemCount() / d_data->numCols;
+ if ( itemCount() % d_data->numCols )
+ d_data->numRows++;
+
+ QList<QRect> itemGeometries = layoutItems( rect, d_data->numCols );
+
+ int index = 0;
+ for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
+ it != d_data->itemList.end(); ++it )
+ {
+ ( *it )->setGeometry( itemGeometries[index] );
+ index++;
+ }
+}
+
+/*!
+ Calculate the number of columns for a given width. It tries to
+ use as many columns as possible (limited by maxCols())
+
+ \param width Available width for all columns
+ \sa maxCols(), setMaxCols()
+*/
+
+uint QwtDynGridLayout::columnsForWidth( int width ) const
+{
+ if ( isEmpty() )
+ return 0;
+
+ uint maxCols = itemCount();
+ if ( d_data->maxCols > 0 )
+ maxCols = qMin( d_data->maxCols, maxCols );
+
+ if ( maxRowWidth( maxCols ) <= width )
+ return maxCols;
+
+ for ( uint numCols = 2; numCols <= maxCols; numCols++ )
+ {
+ const int rowWidth = maxRowWidth( numCols );
+ if ( rowWidth > width )
+ return numCols - 1;
+ }
+
+ return 1; // At least 1 column
+}
+
+/*!
+ Calculate the width of a layout for a given number of
+ columns.
+
+ \param numCols Given number of columns
+ \param itemWidth Array of the width hints for all items
+*/
+int QwtDynGridLayout::maxRowWidth( int numCols ) const
+{
+ int col;
+
+ QVector<int> colWidth( numCols );
+ for ( col = 0; col < numCols; col++ )
+ colWidth[col] = 0;
+
+ if ( d_data->isDirty )
+ d_data->updateLayoutCache();
+
+ for ( int index = 0;
+ index < d_data->itemSizeHints.count(); index++ )
+ {
+ col = index % numCols;
+ colWidth[col] = qMax( colWidth[col],
+ d_data->itemSizeHints[int( index )].width() );
+ }
+
+ int rowWidth = 2 * margin() + ( numCols - 1 ) * spacing();
+ for ( col = 0; col < numCols; 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 numCols columns and a given rect.
+
+ \param rect Rect where to place the items
+ \param numCols Number of columns
+ \return item geometries
+*/
+
+QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
+ uint numCols ) const
+{
+ QList<QRect> itemGeometries;
+ if ( numCols == 0 || isEmpty() )
+ return itemGeometries;
+
+ uint numRows = itemCount() / numCols;
+ if ( numCols % itemCount() )
+ numRows++;
+
+ if ( numRows == 0 )
+ return itemGeometries;
+
+ QVector<int> rowHeight( numRows );
+ QVector<int> colWidth( numCols );
+
+ layoutGrid( numCols, rowHeight, colWidth );
+
+ bool expandH, expandV;
+ expandH = expandingDirections() & Qt::Horizontal;
+ expandV = expandingDirections() & Qt::Vertical;
+
+ if ( expandH || expandV )
+ stretchGrid( rect, numCols, rowHeight, colWidth );
+
+ const int maxCols = d_data->maxCols;
+ d_data->maxCols = numCols;
+ const QRect alignedRect = alignmentRect( rect );
+ d_data->maxCols = maxCols;
+
+ const int xOffset = expandH ? 0 : alignedRect.x();
+ const int yOffset = expandV ? 0 : alignedRect.y();
+
+ QVector<int> colX( numCols );
+ 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 < numCols; 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 / numCols;
+ const int col = i % numCols;
+
+ 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 numCols columns.
+
+ \param numCols 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 numCols,
+ QVector<int>& rowHeight, QVector<int>& colWidth ) const
+{
+ if ( numCols <= 0 )
+ return;
+
+ if ( d_data->isDirty )
+ d_data->updateLayoutCache();
+
+ for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
+ {
+ const int row = index / numCols;
+ const int col = index % numCols;
+
+ 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 the width w.
+ \sa hasHeightForWidth()
+*/
+int QwtDynGridLayout::heightForWidth( int width ) const
+{
+ if ( isEmpty() )
+ return 0;
+
+ const uint numCols = columnsForWidth( width );
+ uint numRows = itemCount() / numCols;
+ if ( itemCount() % numCols )
+ numRows++;
+
+ QVector<int> rowHeight( numRows );
+ QVector<int> colWidth( numCols );
+
+ layoutGrid( numCols, 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.
+
+ \sa setExpanding(), expanding()
+*/
+void QwtDynGridLayout::stretchGrid( const QRect &rect,
+ uint numCols, QVector<int>& rowHeight, QVector<int>& colWidth ) const
+{
+ if ( numCols == 0 || isEmpty() )
+ return;
+
+ bool expandH, expandV;
+ expandH = expandingDirections() & Qt::Horizontal;
+ expandV = expandingDirections() & Qt::Vertical;
+
+ if ( expandH )
+ {
+ int xDelta = rect.width() - 2 * margin() - ( numCols - 1 ) * spacing();
+ for ( uint col = 0; col < numCols; col++ )
+ xDelta -= colWidth[col];
+
+ if ( xDelta > 0 )
+ {
+ for ( uint col = 0; col < numCols; col++ )
+ {
+ const int space = xDelta / ( numCols - col );
+ colWidth[col] += space;
+ xDelta -= space;
+ }
+ }
+ }
+
+ if ( expandV )
+ {
+ uint numRows = itemCount() / numCols;
+ if ( itemCount() % numCols )
+ 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 maxCols() > 0 it is the size for
+ a grid with maxCols() columns, otherwise it is the size for
+ a grid with only one row.
+
+ \sa maxCols(), setMaxCols()
+*/
+QSize QwtDynGridLayout::sizeHint() const
+{
+ if ( isEmpty() )
+ return QSize();
+
+ uint numCols = itemCount();
+ if ( d_data->maxCols > 0 )
+ numCols = qMin( d_data->maxCols, numCols );
+
+ uint numRows = itemCount() / numCols;
+ if ( itemCount() % numCols )
+ numRows++;
+
+ QVector<int> rowHeight( numRows );
+ QVector<int> colWidth( numCols );
+
+ layoutGrid( numCols, rowHeight, colWidth );
+
+ int h = 2 * margin() + ( numRows - 1 ) * spacing();
+ for ( uint row = 0; row < numRows; row++ )
+ h += rowHeight[row];
+
+ int w = 2 * margin() + ( numCols - 1 ) * spacing();
+ for ( uint col = 0; col < numCols; col++ )
+ w += colWidth[col];
+
+ return QSize( w, h );
+}
+
+/*!
+ \return Number of rows of the current layout.
+ \sa numCols()
+ \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::numCols() const
+{
+ return d_data->numCols;
+}
diff --git a/src/libpcp_qwt/src/qwt_dyngrid_layout.h b/src/libpcp_qwt/src/qwt_dyngrid_layout.h
new file mode 100644
index 0000000..0b835f0
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_dyngrid_layout.h
@@ -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 maxCols()).
+*/
+
+class QWT_EXPORT QwtDynGridLayout : public QLayout
+{
+ Q_OBJECT
+public:
+ explicit QwtDynGridLayout( QWidget *, int margin = 0, int space = -1 );
+ explicit QwtDynGridLayout( int space = -1 );
+
+ virtual ~QwtDynGridLayout();
+
+ virtual void invalidate();
+
+ void setMaxCols( uint maxCols );
+ uint maxCols() const;
+
+ uint numRows () const;
+ uint numCols () 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 numCols ) 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 numCols,
+ QVector<int>& rowHeight, QVector<int>& colWidth ) const;
+ void stretchGrid( const QRect &rect, uint numCols,
+ QVector<int>& rowHeight, QVector<int>& colWidth ) const;
+
+private:
+ void init();
+ int maxRowWidth( int numCols ) const;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_event_pattern.cpp b/src/libpcp_qwt/src/qwt_event_pattern.cpp
new file mode 100644
index 0000000..24bcbbc
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_event_pattern.cpp
@@ -0,0 +1,274 @@
+/* -*- 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 )
+{
+ const int altButton = Qt::AltModifier;
+ const int controlButton = Qt::ControlModifier;
+ const int shiftButton = Qt::ShiftModifier;
+
+ d_mousePattern.resize( MousePatternCount );
+
+ switch ( numButtons )
+ {
+ case 1:
+ {
+ setMousePattern( MouseSelect1, Qt::LeftButton );
+ setMousePattern( MouseSelect2, Qt::LeftButton, controlButton );
+ setMousePattern( MouseSelect3, Qt::LeftButton, altButton );
+ break;
+ }
+ case 2:
+ {
+ setMousePattern( MouseSelect1, Qt::LeftButton );
+ setMousePattern( MouseSelect2, Qt::RightButton );
+ setMousePattern( MouseSelect3, Qt::LeftButton, altButton );
+ break;
+ }
+ default:
+ {
+ setMousePattern( MouseSelect1, Qt::LeftButton );
+ setMousePattern( MouseSelect2, Qt::RightButton );
+ setMousePattern( MouseSelect3, Qt::MidButton );
+ }
+ }
+ for ( int i = 0; i < 3; i++ )
+ {
+ setMousePattern( MouseSelect4 + i,
+ d_mousePattern[MouseSelect1 + i].button,
+ d_mousePattern[MouseSelect1 + i].state | shiftButton );
+ }
+}
+
+/*!
+ 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 state State
+
+ \sa QMouseEvent
+*/
+void QwtEventPattern::setMousePattern( uint pattern, int button, int state )
+{
+ if ( pattern < ( uint )d_mousePattern.count() )
+ {
+ d_mousePattern[int( pattern )].button = button;
+ d_mousePattern[int( pattern )].state = state;
+ }
+}
+
+/*!
+ Change one key pattern
+
+ \param pattern Index of the pattern
+ \param key Key
+ \param state State
+
+ \sa QKeyEvent
+*/
+void QwtEventPattern::setKeyPattern( uint pattern, int key, int state )
+{
+ if ( pattern < ( uint )d_keyPattern.count() )
+ {
+ d_keyPattern[int( pattern )].key = key;
+ d_keyPattern[int( pattern )].state = state;
+ }
+}
+
+//! 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 patterns
+const QVector<QwtEventPattern::MousePattern> &
+QwtEventPattern::mousePattern() const
+{
+ return d_mousePattern;
+}
+
+//! Return key patterns
+const QVector<QwtEventPattern::KeyPattern> &
+QwtEventPattern::keyPattern() const
+{
+ return d_keyPattern;
+}
+
+//! Return ,ouse patterns
+QVector<QwtEventPattern::MousePattern> &QwtEventPattern::mousePattern()
+{
+ return d_mousePattern;
+}
+
+//! Return Key patterns
+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 pattern Index of the event pattern
+ \param event Mouse event
+ \return true if matches
+
+ \sa keyMatch()
+*/
+bool QwtEventPattern::mouseMatch( uint pattern,
+ const QMouseEvent *event ) const
+{
+ bool ok = false;
+
+ if ( event && pattern < ( uint )d_mousePattern.count() )
+ ok = mouseMatch( d_mousePattern[int( pattern )], event );
+
+ return ok;
+}
+
+/*!
+ \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->button() != pattern.button )
+ return false;
+
+ const bool matched =
+ ( event->modifiers() & Qt::KeyboardModifierMask ) ==
+ ( int )( pattern.state & Qt::KeyboardModifierMask );
+
+ return matched;
+}
+
+/*!
+ \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 Index of the event pattern
+ \param event Key event
+ \return true if matches
+
+ \sa mouseMatch()
+*/
+bool QwtEventPattern::keyMatch( uint pattern,
+ const QKeyEvent *event ) const
+{
+ bool ok = false;
+
+ if ( event && pattern < ( uint )d_keyPattern.count() )
+ ok = keyMatch( d_keyPattern[int( pattern )], event );
+
+ return ok;
+}
+
+/*!
+ \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->key() != pattern.key )
+ return false;
+
+ const bool matched =
+ ( event->modifiers() & Qt::KeyboardModifierMask ) ==
+ ( int )( pattern.state & Qt::KeyboardModifierMask );
+
+ return matched;
+}
diff --git a/src/libpcp_qwt/src/qwt_event_pattern.h b/src/libpcp_qwt/src/qwt_event_pattern.h
new file mode 100644
index 0000000..a88f5f4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_event_pattern.h
@@ -0,0 +1,225 @@
+/* -*- 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
+
+ The default initialization for 3 button mice is:
+ - MouseSelect1\n
+ Qt::LeftButton
+ - MouseSelect2\n
+ Qt::RightButton
+ - MouseSelect3\n
+ Qt::MidButton
+ - MouseSelect4\n
+ Qt::LeftButton + Qt::ShiftButton
+ - MouseSelect5\n
+ Qt::RightButton + Qt::ShiftButton
+ - MouseSelect6\n
+ Qt::MidButton + Qt::ShiftButton
+
+ The default initialization for 2 button mice is:
+ - MouseSelect1\n
+ Qt::LeftButton
+ - MouseSelect2\n
+ Qt::RightButton
+ - MouseSelect3\n
+ Qt::LeftButton + Qt::AltButton
+ - MouseSelect4\n
+ Qt::LeftButton + Qt::ShiftButton
+ - MouseSelect5\n
+ Qt::RightButton + Qt::ShiftButton
+ - MouseSelect6\n
+ Qt::LeftButton + Qt::AltButton + Qt::ShiftButton
+
+ The default initialization for 1 button mice is:
+ - MouseSelect1\n
+ Qt::LeftButton
+ - MouseSelect2\n
+ Qt::LeftButton + Qt::ControlButton
+ - MouseSelect3\n
+ Qt::LeftButton + Qt::AltButton
+ - MouseSelect4\n
+ Qt::LeftButton + Qt::ShiftButton
+ - MouseSelect5\n
+ Qt::LeftButton + Qt::ControlButton + Qt::ShiftButton
+ - MouseSelect6\n
+ Qt::LeftButton + Qt::AltButton + Qt::ShiftButton
+
+ \sa initMousePattern()
+ */
+
+ enum MousePatternCode
+ {
+ MouseSelect1,
+ MouseSelect2,
+ MouseSelect3,
+ MouseSelect4,
+ MouseSelect5,
+ MouseSelect6,
+
+ MousePatternCount
+ };
+
+ /*!
+ \brief Symbolic keyboard input codes
+
+ Default initialization:
+ - KeySelect1\n
+ Qt::Key_Return
+ - KeySelect2\n
+ Qt::Key_Space
+ - KeyAbort\n
+ Qt::Key_Escape
+
+ - KeyLeft\n
+ Qt::Key_Left
+ - KeyRight\n
+ Qt::Key_Right
+ - KeyUp\n
+ Qt::Key_Up
+ - KeyDown\n
+ Qt::Key_Down
+
+ - KeyUndo\n
+ Qt::Key_Minus
+ - KeyRedo\n
+ Qt::Key_Plus
+ - KeyHome\n
+ Qt::Key_Escape
+ */
+ enum KeyPatternCode
+ {
+ KeySelect1,
+ KeySelect2,
+ KeyAbort,
+
+ KeyLeft,
+ KeyRight,
+ KeyUp,
+ KeyDown,
+
+ KeyRedo,
+ KeyUndo,
+ KeyHome,
+
+ KeyPatternCount
+ };
+
+ //! A pattern for mouse events
+ class MousePattern
+ {
+ public:
+ //! Constructor
+ MousePattern( int btn = Qt::NoButton, int st = Qt::NoButton )
+ {
+ button = btn;
+ state = st;
+ }
+
+ //! Button code
+ int button;
+
+ //! State
+ int state;
+ };
+
+ //! A pattern for key events
+ class KeyPattern
+ {
+ public:
+ //! Constructor
+ KeyPattern( int k = 0, int st = Qt::NoButton )
+ {
+ key = k;
+ state = st;
+ }
+
+ //! Key code
+ int key;
+
+ //! State
+ int state;
+ };
+
+ QwtEventPattern();
+ virtual ~QwtEventPattern();
+
+ void initMousePattern( int numButtons );
+ void initKeyPattern();
+
+ void setMousePattern( uint pattern, int button, int state = Qt::NoButton );
+ void setKeyPattern( uint pattern, int key, int state = Qt::NoButton );
+
+ 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( uint pattern, const QMouseEvent * ) const;
+ bool keyMatch( uint pattern, 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.state == b2.state;
+}
+
+//! Compare operator
+inline bool operator==( QwtEventPattern::KeyPattern b1,
+ QwtEventPattern::KeyPattern b2 )
+{
+ return b1.key == b2.key && b1.state == b2.state;
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_global.h b/src/libpcp_qwt/src/qwt_global.h
new file mode 100644
index 0000000..6b3f830
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_global.h
@@ -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 0x060002
+#define QWT_VERSION_STR "6.0.2"
+
+#if defined(_MSC_VER) /* MSVC Compiler */
+/* template-class specialization 'identifier' is already instantiated */
+#pragma warning(disable: 4660)
+#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
+
+// #define QWT_NO_COMPAT 1 // disable withdrawn functionality
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_interval.cpp b/src/libpcp_qwt/src/qwt_interval.cpp
new file mode 100644
index 0000000..f835567
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_interval.cpp
@@ -0,0 +1,334 @@
+/* -*- 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;
+}
+
+//! Intersect 2 intervals
+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;
+}
+
+//! Unites this interval with the given interval.
+QwtInterval& QwtInterval::operator|=( const QwtInterval & interval )
+{
+ *this = *this | interval;
+ return *this;
+}
+
+//! Intersects this interval with the given interval.
+QwtInterval& QwtInterval::operator&=( const QwtInterval & interval )
+{
+ *this = *this & interval;
+ return *this;
+}
+
+/*!
+ Test if two intervals overlap
+*/
+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 );
+}
+
+/*!
+ 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
+ \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
diff --git a/src/libpcp_qwt/src/qwt_interval.h b/src/libpcp_qwt/src/qwt_interval.h
new file mode 100644
index 0000000..6e30920
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_interval.h
@@ -0,0 +1,296 @@
+/* -*- 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"
+#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 minValue, double maxValue ) 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()
+*/
+inline bool QwtInterval::isValid() const
+{
+ if ( ( d_borderFlags & ExcludeBorders ) == 0 )
+ return d_minValue <= d_maxValue;
+ else
+ return d_minValue < d_maxValue;
+}
+
+/*!
+ Return the width of an interval
+ The width of invalid intervals is 0.0, otherwise the result is
+ maxValue() - minValue().
+
+ \sa isValid()
+*/
+inline double QwtInterval::width() const
+{
+ return isValid() ? ( d_maxValue - d_minValue ) : 0.0;
+}
+
+/*!
+ Intersection of two intervals
+ \sa intersect()
+*/
+inline QwtInterval QwtInterval::operator&(
+ const QwtInterval &interval ) const
+{
+ return intersect( interval );
+}
+
+/*!
+ Union of two intervals
+ \sa unite()
+*/
+inline QwtInterval QwtInterval::operator|(
+ const QwtInterval &interval ) const
+{
+ return unite( interval );
+}
+
+//! Compare two intervals
+inline bool QwtInterval::operator==( const QwtInterval &other ) const
+{
+ return ( d_minValue == other.d_minValue ) &&
+ ( d_maxValue == other.d_maxValue ) &&
+ ( d_borderFlags == other.d_borderFlags );
+}
+
+//! Compare two intervals
+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 )
+
+#ifndef QT_NO_DEBUG_STREAM
+QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & );
+#endif
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_interval_symbol.cpp b/src/libpcp_qwt/src/qwt_interval_symbol.cpp
new file mode 100644
index 0000000..e3cef16
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_interval_symbol.cpp
@@ -0,0 +1,300 @@
+/* -*- 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;
+}
+
+/*!
+ 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:;
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_interval_symbol.h b/src/libpcp_qwt/src/qwt_interval_symbol.h
new file mode 100644
index 0000000..3ea4fe4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_interval_symbol.h
@@ -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& b );
+ const QBrush& brush() const;
+
+ 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
diff --git a/src/libpcp_qwt/src/qwt_knob.cpp b/src/libpcp_qwt/src/qwt_knob.cpp
new file mode 100644
index 0000000..2e41879
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_knob.cpp
@@ -0,0 +1,665 @@
+/* -*- 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 <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
+
+class QwtKnob::PrivateData
+{
+public:
+ PrivateData()
+ {
+ angle = 0.0;
+ nTurns = 0.0;
+ borderWidth = 2;
+ borderDist = 4;
+ totalAngle = 270.0;
+ scaleDist = 4;
+ markerStyle = QwtKnob::Notch;
+ maxScaleTicks = 11;
+ knobStyle = QwtKnob::Raised;
+ knobWidth = 50;
+ markerSize = 8;
+ }
+
+ QwtKnob::KnobStyle knobStyle;
+ QwtKnob::MarkerStyle markerStyle;
+
+ int borderWidth;
+ int borderDist;
+ int scaleDist;
+ int maxScaleTicks;
+ int knobWidth;
+ int markerSize;
+
+ double angle;
+ double totalAngle;
+ double nTurns;
+
+ mutable QRectF knobRect; // bounding rect of the knob without scale
+};
+
+/*!
+ Constructor
+ \param parent Parent widget
+*/
+QwtKnob::QwtKnob( QWidget* parent ):
+ QwtAbstractSlider( Qt::Horizontal, parent )
+{
+ initKnob();
+}
+
+void QwtKnob::initKnob()
+{
+ d_data = new PrivateData;
+
+ setScaleDraw( new QwtRoundScaleDraw() );
+
+ setUpdateTime( 50 );
+ setTotalAngle( 270.0 );
+ recalcAngle();
+ setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+
+ setRange( 0.0, 10.0, 1.0 );
+ setValue( 0.0 );
+}
+
+//! 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 default angle is 270 degrees. It is possible to specify
+ an angle of more than 360 degrees so that the knob can be
+ turned several times around its axis.
+*/
+void QwtKnob::setTotalAngle ( double angle )
+{
+ if ( angle < 10.0 )
+ d_data->totalAngle = 10.0;
+ else
+ d_data->totalAngle = angle;
+
+ scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
+ 0.5 * d_data->totalAngle );
+ layoutKnob( true );
+}
+
+//! Return the total angle
+double QwtKnob::totalAngle() const
+{
+ return d_data->totalAngle;
+}
+
+/*!
+ 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 );
+}
+
+/*!
+ \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() );
+}
+
+/*!
+ \brief Notify change of value
+
+ Sets the knob's value to the nearest multiple
+ of the step size.
+*/
+void QwtKnob::valueChange()
+{
+ recalcAngle();
+ update();
+ QwtAbstractSlider::valueChange();
+}
+
+/*!
+ \brief Determine the value corresponding to a specified position
+
+ Called by QwtAbstractSlider
+ \param pos point
+*/
+double QwtKnob::getValue( const QPoint &pos )
+{
+ const double dx = rect().center().x() - pos.x();
+ const double dy = rect().center().y() - pos.y();
+
+ const double arc = qAtan2( -dx, dy ) * 180.0 / M_PI;
+
+ double newValue = 0.5 * ( minValue() + maxValue() )
+ + ( arc + d_data->nTurns * 360.0 ) * ( maxValue() - minValue() )
+ / d_data->totalAngle;
+
+ const double oneTurn = qFabs( maxValue() - minValue() ) * 360.0 / d_data->totalAngle;
+ const double eqValue = value() + mouseOffset();
+
+ if ( qFabs( newValue - eqValue ) > 0.5 * oneTurn )
+ {
+ if ( newValue < eqValue )
+ newValue += oneTurn;
+ else
+ newValue -= oneTurn;
+ }
+
+ return newValue;
+}
+
+/*!
+ \brief Set the scrolling mode and direction
+
+ Called by QwtAbstractSlider
+ \param pos Point in question
+ \param scrollMode Scrolling mode
+ \param direction Direction
+*/
+void QwtKnob::getScrollMode( const QPoint &pos,
+ QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const
+{
+ const double r = 0.5 * d_data->knobRect.width();
+ const double dx = d_data->knobRect.x() + r - pos.x();
+ const double dy = d_data->knobRect.y() + r - pos.y();
+
+ if ( qwtSqr( dx ) + qwtSqr( dy ) <= qwtSqr( r ) )
+ {
+ // point is inside the knob
+
+ scrollMode = QwtAbstractSlider::ScrMouse;
+ direction = 0;
+ }
+ else // point lies outside
+ {
+ scrollMode = QwtAbstractSlider::ScrTimer;
+
+ double arc = qAtan2( double( -dx ), double( dy ) ) * 180.0 / M_PI;
+ if ( arc < d_data->angle )
+ direction = -1;
+ else if ( arc > d_data->angle )
+ direction = 1;
+ else
+ direction = 0;
+ }
+}
+
+/*!
+ \brief Notify a change of the range
+
+ Called by QwtAbstractSlider
+*/
+void QwtKnob::rangeChange()
+{
+ if ( autoScale() )
+ rescale( minValue(), maxValue() );
+
+ layoutKnob( true );
+ recalcAngle();
+}
+
+/*!
+ Qt Resize Event
+ \param event Resize event
+*/
+void QwtKnob::resizeEvent( QResizeEvent *event )
+{
+ Q_UNUSED( event );
+ layoutKnob( false );
+}
+
+/*!
+ Handle QEvent::StyleChange and QEvent::FontChange;
+ \param event Change event
+*/
+void QwtKnob::changeEvent( QEvent *event )
+{
+ switch( event->type() )
+ {
+ case QEvent::StyleChange:
+ case QEvent::FontChange:
+ layoutKnob( true );
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Recalculate the knob's geometry and layout based on
+ the current rect and fonts.
+
+ \param update_geometry notify the layout system and call update
+ to redraw the scale
+*/
+void QwtKnob::layoutKnob( bool update_geometry )
+{
+ const double d = d_data->knobWidth;
+
+ d_data->knobRect.setWidth( d );
+ d_data->knobRect.setHeight( d );
+ d_data->knobRect.moveCenter( rect().center() );
+
+ scaleDraw()->setRadius( 0.5 * d + d_data->scaleDist );
+ scaleDraw()->moveCenter( rect().center() );
+
+ if ( update_geometry )
+ {
+ updateGeometry();
+ update();
+ }
+}
+
+/*!
+ Repaint the knob
+ \param event Paint event
+*/
+void QwtKnob::paintEvent( QPaintEvent *event )
+{
+ 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 ( !d_data->knobRect.contains( event->region().boundingRect() ) )
+ scaleDraw()->draw( &painter, palette() );
+
+ drawKnob( &painter, d_data->knobRect );
+ drawMarker( &painter, d_data->knobRect, d_data->angle );
+
+ painter.setRenderHint( QPainter::Antialiasing, false );
+
+ if ( hasFocus() )
+ QwtPainter::drawFocusRect( &painter, this );
+}
+
+/*!
+ \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::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;
+ }
+ 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
+*/
+void QwtKnob::drawMarker( QPainter *painter,
+ const QRectF &rect, double angle ) const
+{
+ if ( d_data->markerStyle == NoMarker || !isValid() )
+ return;
+
+ const double radians = angle * M_PI / 180.0;
+ 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;
+
+ switch ( d_data->markerStyle )
+ {
+ case Notch:
+ case Nub:
+ {
+ const double dotWidth =
+ qMin( double( d_data->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( d_data->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 - d_data->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;
+ }
+#if 0
+ case Triangle:
+ {
+ const double rb = qMax( radius - d_data->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::Text ) );
+ painter->drawPolygon( polygon );
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+}
+
+/*!
+ \brief Change the knob's width.
+
+ The specified width must be >= 5, or it will be clipped.
+ \param width New width
+*/
+void QwtKnob::setKnobWidth( int width )
+{
+ d_data->knobWidth = qMax( width, 5 );
+ layoutKnob( true );
+}
+
+//! 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 );
+ layoutKnob( true );
+}
+
+//! Return the border width
+int QwtKnob::borderWidth() const
+{
+ return d_data->borderWidth;
+}
+
+/*!
+ \brief Set the size of the marker
+ \sa markerSize(), markerStyle()
+*/
+void QwtKnob::setMarkerSize( int size )
+{
+ if ( d_data->markerSize != size )
+ {
+ d_data->markerSize = size;
+ update();
+ }
+}
+
+//! Return the marker size
+int QwtKnob::markerSize() const
+{
+ return d_data->markerSize;
+}
+
+/*!
+ \brief Recalculate the marker angle corresponding to the
+ current value
+*/
+void QwtKnob::recalcAngle()
+{
+ // calculate the angle corresponding to the value
+ if ( maxValue() == minValue() )
+ {
+ d_data->angle = 0;
+ d_data->nTurns = 0;
+ }
+ else
+ {
+ d_data->angle = ( value() - 0.5 * ( minValue() + maxValue() ) )
+ / ( maxValue() - minValue() ) * d_data->totalAngle;
+ d_data->nTurns = qFloor( ( d_data->angle + 180.0 ) / 360.0 );
+ d_data->angle = d_data->angle - d_data->nTurns * 360.0;
+ }
+}
+
+
+/*!
+ Recalculates the layout
+ \sa layoutKnob()
+*/
+void QwtKnob::scaleChange()
+{
+ layoutKnob( true );
+}
+
+/*!
+ \return minimumSizeHint()
+*/
+QSize QwtKnob::sizeHint() const
+{
+ const QSize hint = minimumSizeHint();
+ return hint.expandedTo( QApplication::globalStrut() );
+}
+
+/*!
+ \brief Return a minimum size hint
+ \warning The return value of QwtKnob::minimumSizeHint() depends on the
+ font and the scale.
+*/
+QSize QwtKnob::minimumSizeHint() const
+{
+ // Add the scale radial thickness to the knobWidth
+ const int sh = qCeil( scaleDraw()->extent( font() ) );
+ const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
+
+ return QSize( d, d );
+}
diff --git a/src/libpcp_qwt/src/qwt_knob.h b/src/libpcp_qwt/src/qwt_knob.h
new file mode 100644
index 0000000..355b4c5
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_knob.h
@@ -0,0 +1,159 @@
+/* -*- 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"
+#include "qwt_abstract_scale.h"
+
+class QwtRoundScaleDraw;
+
+/*!
+ \brief The Knob Widget
+
+ The QwtKnob widget imitates look and behaviour of a volume knob on a radio.
+ It contains a scale around the knob which is set up automatically or can
+ be configured manually (see QwtAbstractScale).
+ Automatic scrolling is enabled when the user presses a mouse
+ button on the scale. For a description of signals, slots and other
+ members, see QwtAbstractSlider.
+
+ \image html knob.png
+ \sa QwtAbstractSlider and QwtAbstractScale for the descriptions
+ of the inherited members.
+*/
+
+class QWT_EXPORT QwtKnob : public QwtAbstractSlider, public QwtAbstractScale
+{
+ Q_OBJECT
+
+ Q_ENUMS ( KnobStyle )
+ Q_ENUMS ( MarkerStyle )
+
+ Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle )
+ Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle )
+ Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth )
+ Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
+ Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle )
+ 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.
+ NoStyle = -1,
+
+ //! Build a gradient from QPalette::Midlight and QPalette::Button
+ Raised,
+
+ /*!
+ Build a gradient from QPalette::Midlight, QPalette::Button
+ and QPalette::Midlight
+ */
+ Sunken
+ };
+
+ /*!
+ \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 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 setKnobWidth( int w );
+ int knobWidth() const;
+
+ void setTotalAngle ( double angle );
+ double totalAngle() const;
+
+ void setKnobStyle( KnobStyle );
+ KnobStyle knobStyle() const;
+
+ void setBorderWidth( int bw );
+ 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();
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void changeEvent( QEvent * );
+
+ virtual void drawKnob( QPainter *, const QRectF & ) const;
+ virtual void drawMarker( QPainter *,
+ const QRectF &, double arc ) const;
+
+ virtual double getValue( const QPoint &p );
+ virtual void getScrollMode( const QPoint &,
+ QwtAbstractSlider::ScrollMode &, int &direction ) const;
+
+private:
+ void initKnob();
+ void layoutKnob( bool update );
+ void recalcAngle();
+
+ virtual void valueChange();
+ virtual void rangeChange();
+ virtual void scaleChange();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_legend.cpp b/src/libpcp_qwt/src/qwt_legend.cpp
new file mode 100644
index 0000000..f4797e6
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_legend.cpp
@@ -0,0 +1,519 @@
+/* -*- 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_itemmanager.h"
+#include "qwt_legend_item.h"
+#include "qwt_dyngrid_layout.h"
+#include "qwt_math.h"
+#include <qapplication.h>
+#include <qmap.h>
+#include <qscrollbar.h>
+#include <qscrollarea.h>
+
+class QwtLegend::PrivateData
+{
+public:
+ class LegendMap
+ {
+ public:
+ void insert( const QwtLegendItemManager *, QWidget * );
+
+ void remove( const QwtLegendItemManager * );
+ void remove( QWidget * );
+
+ void clear();
+
+ uint count() const;
+
+ inline const QWidget *find( const QwtLegendItemManager * ) const;
+ inline QWidget *find( const QwtLegendItemManager * );
+
+ inline const QwtLegendItemManager *find( const QWidget * ) const;
+ inline QwtLegendItemManager *find( const QWidget * );
+
+ const QMap<QWidget *, const QwtLegendItemManager *> &widgetMap() const;
+ QMap<QWidget *, const QwtLegendItemManager *> &widgetMap();
+
+ private:
+ QMap<QWidget *, const QwtLegendItemManager *> d_widgetMap;
+ QMap<const QwtLegendItemManager *, QWidget *> d_itemMap;
+ };
+
+ QwtLegend::LegendItemMode itemMode;
+
+ LegendMap map;
+
+ class LegendView;
+ LegendView *view;
+};
+
+class QwtLegend::PrivateData::LegendView: public QScrollArea
+{
+public:
+ LegendView( QWidget *parent ):
+ QScrollArea( parent )
+ {
+ setFocusPolicy( Qt::NoFocus );
+
+ 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 viewportEvent( QEvent *e )
+ {
+ bool ok = QScrollArea::viewportEvent( e );
+
+ if ( e->type() == QEvent::Resize )
+ {
+ QEvent event( QEvent::LayoutRequest );
+ QApplication::sendEvent( contentsWidget, &event );
+ }
+ 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 );
+ }
+
+ QWidget *contentsWidget;
+};
+
+void QwtLegend::PrivateData::LegendMap::insert(
+ const QwtLegendItemManager *item, QWidget *widget )
+{
+ d_itemMap.insert( item, widget );
+ d_widgetMap.insert( widget, item );
+}
+
+void QwtLegend::PrivateData::LegendMap::remove( const QwtLegendItemManager *item )
+{
+ QWidget *widget = d_itemMap[item];
+ d_itemMap.remove( item );
+ d_widgetMap.remove( widget );
+}
+
+void QwtLegend::PrivateData::LegendMap::remove( QWidget *widget )
+{
+ const QwtLegendItemManager *item = d_widgetMap[widget];
+ d_itemMap.remove( item );
+ d_widgetMap.remove( widget );
+}
+
+void QwtLegend::PrivateData::LegendMap::clear()
+{
+
+ /*
+ We can't delete the widgets in the following loop, because
+ we would get ChildRemoved events, changing d_itemMap, while
+ we are iterating.
+ */
+
+ QList<const QWidget *> widgets;
+
+ QMap<const QwtLegendItemManager *, QWidget *>::const_iterator it;
+ for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it )
+ widgets.append( it.value() );
+
+ d_itemMap.clear();
+ d_widgetMap.clear();
+
+ for ( int i = 0; i < widgets.size(); i++ )
+ delete widgets[i];
+}
+
+uint QwtLegend::PrivateData::LegendMap::count() const
+{
+ return d_itemMap.count();
+}
+
+inline const QWidget *QwtLegend::PrivateData::LegendMap::find(
+ const QwtLegendItemManager *item ) const
+{
+ if ( !d_itemMap.contains( item ) )
+ return NULL;
+
+ return d_itemMap[item];
+}
+
+inline QWidget *QwtLegend::PrivateData::LegendMap::find(
+ const QwtLegendItemManager *item )
+{
+ if ( !d_itemMap.contains( item ) )
+ return NULL;
+
+ return d_itemMap[item];
+}
+
+inline const QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
+ const QWidget *widget ) const
+{
+ QWidget *w = const_cast<QWidget *>( widget );
+ if ( !d_widgetMap.contains( w ) )
+ return NULL;
+
+ return d_widgetMap[w];
+}
+
+inline QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
+ const QWidget *widget )
+{
+ QWidget *w = const_cast<QWidget *>( widget );
+ if ( !d_widgetMap.contains( w ) )
+ return NULL;
+
+ return const_cast<QwtLegendItemManager *>( d_widgetMap[w] );
+}
+
+inline const QMap<QWidget *, const QwtLegendItemManager *> &
+QwtLegend::PrivateData::LegendMap::widgetMap() const
+{
+ return d_widgetMap;
+}
+
+inline QMap<QWidget *, const QwtLegendItemManager *> &
+QwtLegend::PrivateData::LegendMap::widgetMap()
+{
+ return d_widgetMap;
+}
+
+/*!
+ Constructor
+
+ \param parent Parent widget
+*/
+QwtLegend::QwtLegend( QWidget *parent ):
+ QFrame( parent )
+{
+ setFrameStyle( NoFrame );
+
+ d_data = new QwtLegend::PrivateData;
+ d_data->itemMode = QwtLegend::ReadOnlyItem;
+
+ 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;
+}
+
+//! \sa LegendItemMode
+void QwtLegend::setItemMode( LegendItemMode mode )
+{
+ d_data->itemMode = mode;
+}
+
+//! \sa LegendItemMode
+QwtLegend::LegendItemMode QwtLegend::itemMode() 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;
+}
+
+/*!
+ Insert a new item for a plot item
+ \param plotItem Plot item
+ \param legendItem New legend item
+ \note The parent of item will be changed to contentsWidget()
+*/
+void QwtLegend::insert( const QwtLegendItemManager *plotItem, QWidget *legendItem )
+{
+ if ( legendItem == NULL || plotItem == NULL )
+ return;
+
+ QWidget *contentsWidget = d_data->view->contentsWidget;
+
+ if ( legendItem->parent() != contentsWidget )
+ legendItem->setParent( contentsWidget );
+
+ legendItem->show();
+
+ d_data->map.insert( plotItem, legendItem );
+
+ layoutContents();
+
+ if ( contentsWidget->layout() )
+ {
+ contentsWidget->layout()->addWidget( legendItem );
+
+ // set tab focus chain
+
+ QWidget *w = NULL;
+
+ for ( int i = 0; i < contentsWidget->layout()->count(); i++ )
+ {
+ QLayoutItem *item = contentsWidget->layout()->itemAt( i );
+ if ( w && item->widget() )
+ QWidget::setTabOrder( w, item->widget() );
+
+ w = item->widget();
+ }
+ }
+ if ( parentWidget() && parentWidget()->layout() == NULL )
+ {
+ /*
+ updateGeometry() doesn't post LayoutRequest in certain
+ situations, like when we are 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 ) );
+ }
+}
+
+/*!
+ Find the widget that represents a plot item
+
+ \param plotItem Plot item
+ \return Widget on the legend, or NULL
+*/
+QWidget *QwtLegend::find( const QwtLegendItemManager *plotItem ) const
+{
+ return d_data->map.find( plotItem );
+}
+
+/*!
+ Find the widget that represents a plot item
+
+ \param legendItem Legend item
+ \return Widget on the legend, or NULL
+*/
+QwtLegendItemManager *QwtLegend::find( const QWidget *legendItem ) const
+{
+ return d_data->map.find( legendItem );
+}
+
+/*!
+ Find the corresponding item for a plotItem and remove it
+ from the item list.
+
+ \param plotItem Plot item
+*/
+void QwtLegend::remove( const QwtLegendItemManager *plotItem )
+{
+ QWidget *legendItem = d_data->map.find( plotItem );
+ d_data->map.remove( legendItem );
+ delete legendItem;
+}
+
+//! Remove all items.
+void QwtLegend::clear()
+{
+ bool doUpdate = updatesEnabled();
+ if ( doUpdate )
+ setUpdatesEnabled( false );
+
+ d_data->map.clear();
+
+ if ( doUpdate )
+ setUpdatesEnabled( true );
+
+ update();
+}
+
+//! 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 the width w.
+ \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;
+}
+
+/*!
+ Adjust contents widget and item layout to the size of the viewport().
+*/
+void QwtLegend::layoutContents()
+{
+ const QSize visibleSize =
+ d_data->view->viewport()->contentsRect().size();
+
+ const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
+ d_data->view->contentsWidget->layout() );
+ if ( tl )
+ {
+ 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 = d_data->view->viewportSize( w, h ).width();
+ if ( w > vpWidth )
+ {
+ w = qMax( vpWidth, minW );
+ h = qMax( tl->heightForWidth( w ), visibleSize.height() );
+ }
+
+ d_data->view->contentsWidget->resize( w, h );
+ }
+}
+
+/*!
+ Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
+ for the contentsWidget().
+
+ \param object Object to be filtered
+ \param event Event
+*/
+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() )
+ {
+ QWidget *w = static_cast< QWidget * >( ce->child() );
+ d_data->map.remove( w );
+ }
+ break;
+ }
+ case QEvent::LayoutRequest:
+ {
+ layoutContents();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return QFrame::eventFilter( object, event );
+}
+
+
+//! Return true, if there are no legend items.
+bool QwtLegend::isEmpty() const
+{
+ return d_data->map.count() == 0;
+}
+
+//! Return the number of legend items.
+uint QwtLegend::itemCount() const
+{
+ return d_data->map.count();
+}
+
+//! Return a list of all legend items
+QList<QWidget *> QwtLegend::legendItems() const
+{
+ const QMap<QWidget *, const QwtLegendItemManager *> &map =
+ d_data->map.widgetMap();
+
+ QList<QWidget *> list;
+
+ QMap<QWidget *, const QwtLegendItemManager *>::const_iterator it;
+ for ( it = map.begin(); it != map.end(); ++it )
+ list += it.key();
+
+ return list;
+} \ No newline at end of file
diff --git a/src/libpcp_qwt/src/qwt_legend.h b/src/libpcp_qwt/src/qwt_legend.h
new file mode 100644
index 0000000..e241783
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_legend.h
@@ -0,0 +1,95 @@
+/* -*- 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 <qframe.h>
+#include <qlist.h>
+
+class QScrollBar;
+class QwtLegendItemManager;
+
+/*!
+ \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 QwtLegendItem.
+
+ \sa QwtLegendItem, QwtLegendItemManager QwtPlot
+*/
+
+class QWT_EXPORT QwtLegend : public QFrame
+{
+ Q_OBJECT
+
+public:
+ /*!
+ \brief Interaction mode for the legend items
+
+ The default is QwtLegend::ReadOnlyItem.
+
+ \sa setItemMode(), itemMode(), QwtLegendItem::IdentifierMode
+ QwtLegendItem::clicked(), QwtLegendItem::checked(),
+ QwtPlot::legendClicked(), QwtPlot::legendChecked()
+ */
+
+ enum LegendItemMode
+ {
+ //! The legend item is not interactive, like a label
+ ReadOnlyItem,
+
+ //! The legend item is clickable, like a push button
+ ClickableItem,
+
+ //! The legend item is checkable, like a checkable button
+ CheckableItem
+ };
+
+ explicit QwtLegend( QWidget *parent = NULL );
+ virtual ~QwtLegend();
+
+ void setItemMode( LegendItemMode );
+ LegendItemMode itemMode() const;
+
+ QWidget *contentsWidget();
+ const QWidget *contentsWidget() const;
+
+ void insert( const QwtLegendItemManager *, QWidget * );
+ void remove( const QwtLegendItemManager * );
+
+ QWidget *find( const QwtLegendItemManager * ) const;
+ QwtLegendItemManager *find( const QWidget * ) const;
+
+ virtual QList<QWidget *> legendItems() const;
+
+ void clear();
+
+ bool isEmpty() const;
+ uint itemCount() const;
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ virtual QSize sizeHint() const;
+ virtual int heightForWidth( int w ) const;
+
+ QScrollBar *horizontalScrollBar() const;
+ QScrollBar *verticalScrollBar() const;
+
+protected:
+ virtual void layoutContents();
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_legend_item.cpp b/src/libpcp_qwt/src/qwt_legend_item.cpp
new file mode 100644
index 0000000..5d59af4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_legend_item.cpp
@@ -0,0 +1,407 @@
+/* -*- 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_item.h"
+#include "qwt_math.h"
+#include "qwt_painter.h"
+#include "qwt_symbol.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 PixmapHeight = 10;
+static const int PixmapWidth = 15;
+static const int ButtonFrame = 2;
+static const int Margin = 2;
+
+static QSize buttonShift( const QwtLegendItem *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 QwtLegendItem::PrivateData
+{
+public:
+ PrivateData():
+ itemMode( QwtLegend::ReadOnlyItem ),
+ isDown( false ),
+ identifierSize( PixmapWidth, PixmapHeight ),
+ spacing( Margin )
+ {
+ }
+
+ QwtLegend::LegendItemMode itemMode;
+ bool isDown;
+
+ QSize identifierSize;
+ QPixmap identifier;
+
+ int spacing;
+};
+
+/*!
+ \param parent Parent widget
+*/
+QwtLegendItem::QwtLegendItem( QWidget *parent ):
+ QwtTextLabel( parent )
+{
+ d_data = new PrivateData;
+ setMargin( Margin );
+ setIndent( Margin + d_data->identifierSize.width() + 2 * d_data->spacing );
+}
+
+//! Destructor
+QwtLegendItem::~QwtLegendItem()
+{
+ delete d_data;
+ d_data = NULL;
+}
+
+/*!
+ Set the text to the legend item
+
+ \param text Text label
+ \sa QwtTextLabel::text()
+*/
+void QwtLegendItem::setText( const QwtText &text )
+{
+ const int flags = Qt::AlignLeft | Qt::AlignVCenter
+ | Qt::TextExpandTabs | Qt::TextWordWrap;
+
+ QwtText txt = text;
+ txt.setRenderFlags( flags );
+
+ QwtTextLabel::setText( txt );
+}
+
+/*!
+ Set the item mode
+ The default is QwtLegend::ReadOnlyItem
+
+ \param mode Item mode
+ \sa itemMode()
+*/
+void QwtLegendItem::setItemMode( QwtLegend::LegendItemMode mode )
+{
+ if ( mode != d_data->itemMode )
+ {
+ d_data->itemMode = mode;
+ d_data->isDown = false;
+
+ setFocusPolicy( mode != QwtLegend::ReadOnlyItem ? Qt::TabFocus : Qt::NoFocus );
+ setMargin( ButtonFrame + Margin );
+
+ updateGeometry();
+ }
+}
+
+/*!
+ Return the item mode
+
+ \sa setItemMode()
+*/
+QwtLegend::LegendItemMode QwtLegendItem::itemMode() const
+{
+ return d_data->itemMode;
+}
+
+/*!
+ Assign the identifier
+ The identifier needs to be created according to the identifierWidth()
+
+ \param identifier Pixmap representing a plot item
+
+ \sa identifier(), identifierWidth()
+*/
+void QwtLegendItem::setIdentifier( const QPixmap &identifier )
+{
+ d_data->identifier = identifier;
+ update();
+}
+
+/*!
+ \return pixmap representing a plot item
+ \sa setIdentifier()
+*/
+QPixmap QwtLegendItem::identifier() const
+{
+ return d_data->identifier;
+}
+
+/*!
+ Set the size for the identifier
+ Default is PixmapWidth x PixmapHeight pixels
+
+ \param size New size
+
+ \sa identifierSize()
+*/
+void QwtLegendItem::setIdentifierSize( const QSize &size )
+{
+ QSize sz = size.expandedTo( QSize( 0, 0 ) );
+ if ( sz != d_data->identifierSize )
+ {
+ d_data->identifierSize = sz;
+ setIndent( margin() + d_data->identifierSize.width()
+ + 2 * d_data->spacing );
+ updateGeometry();
+ }
+}
+/*!
+ Return the width of the identifier
+
+ \sa setIdentifierSize()
+*/
+QSize QwtLegendItem::identifierSize() const
+{
+ return d_data->identifierSize;
+}
+
+/*!
+ Change the spacing
+ \param spacing Spacing
+ \sa spacing(), identifierWidth(), QwtTextLabel::margin()
+*/
+void QwtLegendItem::setSpacing( int spacing )
+{
+ spacing = qMax( spacing, 0 );
+ if ( spacing != d_data->spacing )
+ {
+ d_data->spacing = spacing;
+ setIndent( margin() + d_data->identifierSize.width()
+ + 2 * d_data->spacing );
+ }
+}
+
+/*!
+ Return the spacing
+ \sa setSpacing(), identifierWidth(), QwtTextLabel::margin()
+*/
+int QwtLegendItem::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ Check/Uncheck a the item
+
+ \param on check/uncheck
+ \sa setItemMode()
+*/
+void QwtLegendItem::setChecked( bool on )
+{
+ if ( d_data->itemMode == QwtLegend::CheckableItem )
+ {
+ const bool isBlocked = signalsBlocked();
+ blockSignals( true );
+
+ setDown( on );
+
+ blockSignals( isBlocked );
+ }
+}
+
+//! Return true, if the item is checked
+bool QwtLegendItem::isChecked() const
+{
+ return d_data->itemMode == QwtLegend::CheckableItem && isDown();
+}
+
+//! Set the item being down
+void QwtLegendItem::setDown( bool down )
+{
+ if ( down == d_data->isDown )
+ return;
+
+ d_data->isDown = down;
+ update();
+
+ if ( d_data->itemMode == QwtLegend::ClickableItem )
+ {
+ if ( d_data->isDown )
+ Q_EMIT pressed();
+ else
+ {
+ Q_EMIT released();
+ Q_EMIT clicked();
+ }
+ }
+
+ if ( d_data->itemMode == QwtLegend::CheckableItem )
+ Q_EMIT checked( d_data->isDown );
+}
+
+//! Return true, if the item is down
+bool QwtLegendItem::isDown() const
+{
+ return d_data->isDown;
+}
+
+//! Return a size hint
+QSize QwtLegendItem::sizeHint() const
+{
+ QSize sz = QwtTextLabel::sizeHint();
+ sz.setHeight( qMax( sz.height(), d_data->identifier.height() + 4 ) );
+
+ if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
+ {
+ sz += buttonShift( this );
+ sz = sz.expandedTo( QApplication::globalStrut() );
+ }
+
+ return sz;
+}
+
+//! Paint event
+void QwtLegendItem::paintEvent( QPaintEvent *e )
+{
+ const QRect cr = contentsRect();
+
+ QPainter painter( this );
+ painter.setClipRegion( e->region() );
+
+ if ( d_data->isDown )
+ {
+ qDrawWinButton( &painter, 0, 0, width(), height(),
+ 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->identifier.isNull() )
+ {
+ QRect identRect = cr;
+ identRect.setX( identRect.x() + margin() );
+ if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
+ identRect.setX( identRect.x() + ButtonFrame );
+
+ identRect.setSize( d_data->identifier.size() );
+ identRect.moveCenter( QPoint( identRect.center().x(), cr.center().y() ) );
+
+ painter.drawPixmap( identRect, d_data->identifier );
+ }
+
+ painter.restore();
+}
+
+//! Handle mouse press events
+void QwtLegendItem::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() == Qt::LeftButton )
+ {
+ switch ( d_data->itemMode )
+ {
+ case QwtLegend::ClickableItem:
+ {
+ setDown( true );
+ return;
+ }
+ case QwtLegend::CheckableItem:
+ {
+ setDown( !isDown() );
+ return;
+ }
+ default:;
+ }
+ }
+ QwtTextLabel::mousePressEvent( e );
+}
+
+//! Handle mouse release events
+void QwtLegendItem::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() == Qt::LeftButton )
+ {
+ switch ( d_data->itemMode )
+ {
+ case QwtLegend::ClickableItem:
+ {
+ setDown( false );
+ return;
+ }
+ case QwtLegend::CheckableItem:
+ {
+ return; // do nothing, but accept
+ }
+ default:;
+ }
+ }
+ QwtTextLabel::mouseReleaseEvent( e );
+}
+
+//! Handle key press events
+void QwtLegendItem::keyPressEvent( QKeyEvent *e )
+{
+ if ( e->key() == Qt::Key_Space )
+ {
+ switch ( d_data->itemMode )
+ {
+ case QwtLegend::ClickableItem:
+ {
+ if ( !e->isAutoRepeat() )
+ setDown( true );
+ return;
+ }
+ case QwtLegend::CheckableItem:
+ {
+ if ( !e->isAutoRepeat() )
+ setDown( !isDown() );
+ return;
+ }
+ default:;
+ }
+ }
+
+ QwtTextLabel::keyPressEvent( e );
+}
+
+//! Handle key release events
+void QwtLegendItem::keyReleaseEvent( QKeyEvent *e )
+{
+ if ( e->key() == Qt::Key_Space )
+ {
+ switch ( d_data->itemMode )
+ {
+ case QwtLegend::ClickableItem:
+ {
+ if ( !e->isAutoRepeat() )
+ setDown( false );
+ return;
+ }
+ case QwtLegend::CheckableItem:
+ {
+ return; // do nothing, but accept
+ }
+ default:;
+ }
+ }
+
+ QwtTextLabel::keyReleaseEvent( e );
+}
diff --git a/src/libpcp_qwt/src/qwt_legend_item.h b/src/libpcp_qwt/src/qwt_legend_item.h
new file mode 100644
index 0000000..1d315f6
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_legend_item.h
@@ -0,0 +1,78 @@
+/* -*- 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_ITEM_H
+#define QWT_LEGEND_ITEM_H
+
+#include "qwt_global.h"
+#include "qwt_legend.h"
+#include "qwt_text.h"
+#include "qwt_text_label.h"
+#include <qpixmap.h>
+
+/*!
+ \brief A widget representing something on a QwtLegend().
+*/
+class QWT_EXPORT QwtLegendItem: public QwtTextLabel
+{
+ Q_OBJECT
+public:
+ explicit QwtLegendItem( QWidget *parent = 0 );
+ virtual ~QwtLegendItem();
+
+ void setItemMode( QwtLegend::LegendItemMode );
+ QwtLegend::LegendItemMode itemMode() const;
+
+ void setSpacing( int spacing );
+ int spacing() const;
+
+ virtual void setText( const QwtText & );
+
+ void setIdentifier( const QPixmap & );
+ QPixmap identifier() const;
+
+ void setIdentifierSize( const QSize & );
+ QSize identifierSize() 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 relased
+ 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
diff --git a/src/libpcp_qwt/src/qwt_legend_itemmanager.h b/src/libpcp_qwt/src/qwt_legend_itemmanager.h
new file mode 100644
index 0000000..ccea820
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_legend_itemmanager.h
@@ -0,0 +1,66 @@
+/* -*- 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_ITEM_MANAGER_H
+#define QWT_LEGEND_ITEM_MANAGER_H
+
+#include "qwt_global.h"
+
+class QwtLegend;
+class QWidget;
+class QRectF;
+class QPainter;
+
+/*!
+ \brief Abstract API to bind plot items to the legend
+*/
+
+class QWT_EXPORT QwtLegendItemManager
+{
+public:
+ //! Constructor
+ QwtLegendItemManager()
+ {
+ }
+
+ //! Destructor
+ virtual ~QwtLegendItemManager()
+ {
+ }
+
+ /*!
+ Update the widget that represents the item on the legend
+ \param legend Legend
+ \sa legendItem()
+ */
+ virtual void updateLegend( QwtLegend *legend ) const = 0;
+
+ /*!
+ Allocate the widget that represents the item on the legend
+ \return Allocated widget
+ \sa updateLegend() QwtLegend()
+ */
+
+ virtual QWidget *legendItem() const = 0;
+
+ /*!
+ QwtLegendItem can display an icon-identifier followed
+ by a text. The icon helps to identify a plot item on
+ the plot canvas and depends on the type of information,
+ that is displayed.
+
+ The default implementation paints nothing.
+ */
+ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const
+ {
+ }
+};
+
+#endif
+
diff --git a/src/libpcp_qwt/src/qwt_magnifier.cpp b/src/libpcp_qwt/src/qwt_magnifier.cpp
new file mode 100644
index 0000000..5e8ffb0
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_magnifier.cpp
@@ -0,0 +1,467 @@
+/* -*- 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 ),
+ wheelButtonState( Qt::NoButton ),
+ mouseFactor( 0.95 ),
+ mouseButton( Qt::RightButton ),
+ mouseButtonState( Qt::NoButton ),
+ keyFactor( 0.9 ),
+ zoomInKey( Qt::Key_Plus ),
+ zoomOutKey( Qt::Key_Minus ),
+ zoomInKeyModifiers( Qt::NoModifier ),
+ zoomOutKeyModifiers( Qt::NoModifier ),
+ mousePressed( false )
+ {
+ }
+
+ bool isEnabled;
+
+ double wheelFactor;
+ int wheelButtonState;
+
+ double mouseFactor;
+ int mouseButton;
+ int mouseButtonState;
+
+ double keyFactor;
+ int zoomInKey;
+ int zoomOutKey;
+ int zoomInKeyModifiers;
+ int 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.
+ 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 a mandatory button state for zooming in/out using the wheel.
+ The default button state is Qt::NoButton.
+
+ \param buttonState Button state
+ \sa wheelButtonState()
+*/
+void QwtMagnifier::setWheelButtonState( int buttonState )
+{
+ d_data->wheelButtonState = buttonState;
+}
+
+/*!
+ \return Wheel button state
+ \sa setWheelButtonState()
+*/
+int QwtMagnifier::wheelButtonState() const
+{
+ return d_data->wheelButtonState;
+}
+
+/*!
+ \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 buttonState Button state
+ \sa getMouseButton()
+*/
+void QwtMagnifier::setMouseButton( int button, int buttonState )
+{
+ d_data->mouseButton = button;
+ d_data->mouseButtonState = buttonState;
+}
+
+//! \sa setMouseButton()
+void QwtMagnifier::getMouseButton(
+ int &button, int &buttonState ) const
+{
+ button = d_data->mouseButton;
+ buttonState = d_data->mouseButtonState;
+}
+
+/*!
+ \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, int modifiers )
+{
+ d_data->zoomInKey = key;
+ d_data->zoomInKeyModifiers = modifiers;
+}
+
+//! \sa setZoomInKey()
+void QwtMagnifier::getZoomInKey( int &key, int &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, int modifiers )
+{
+ d_data->zoomOutKey = key;
+ d_data->zoomOutKeyModifiers = modifiers;
+}
+
+//! \sa setZoomOutKey()
+void QwtMagnifier::getZoomOutKey( int &key, int &modifiers ) const
+{
+ key = d_data->zoomOutKey;
+ modifiers = d_data->zoomOutKeyModifiers;
+}
+
+/*!
+ \brief Event filter
+
+ When isEnabled() the mouse events of the observed widget are filtered.
+
+ \param object Object to be filtered
+ \param event Event
+
+ \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( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseMove:
+ {
+ widgetMouseMoveEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ widgetMouseReleaseEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::Wheel:
+ {
+ widgetWheelEvent( ( QWheelEvent * )event );
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ widgetKeyPressEvent( ( QKeyEvent * )event );
+ break;
+ }
+ case QEvent::KeyRelease:
+ {
+ widgetKeyReleaseEvent( ( 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 ( ( mouseEvent->button() != d_data->mouseButton)
+ || parentWidget() == NULL )
+ {
+ return;
+ }
+
+ if ( ( mouseEvent->modifiers() & Qt::KeyboardModifierMask ) !=
+ ( int )( d_data->mouseButtonState & Qt::KeyboardModifierMask ) )
+ {
+ 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() & Qt::KeyboardModifierMask ) !=
+ ( int )( d_data->wheelButtonState & Qt::KeyboardModifierMask ) )
+ {
+ 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 )
+{
+ const int key = keyEvent->key();
+ const int state = keyEvent->modifiers();
+
+ if ( key == d_data->zoomInKey &&
+ state == d_data->zoomInKeyModifiers )
+ {
+ rescale( d_data->keyFactor );
+ }
+ else if ( key == d_data->zoomOutKey &&
+ state == 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() );
+}
+
diff --git a/src/libpcp_qwt/src/qwt_magnifier.h b/src/libpcp_qwt/src/qwt_magnifier.h
new file mode 100644
index 0000000..f2f4bbd
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_magnifier.h
@@ -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( int button, int buttonState = Qt::NoButton );
+ void getMouseButton( int &button, int &buttonState ) const;
+
+ // mouse wheel
+ void setWheelFactor( double );
+ double wheelFactor() const;
+
+ void setWheelButtonState( int buttonState );
+ int wheelButtonState() const;
+
+ // keyboard
+ void setKeyFactor( double );
+ double keyFactor() const;
+
+ void setZoomInKey( int key, int modifiers );
+ void getZoomInKey( int &key, int &modifiers ) const;
+
+ void setZoomOutKey( int key, int modifiers );
+ void getZoomOutKey( int &key, int &modifiers ) 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
diff --git a/src/libpcp_qwt/src/qwt_math.cpp b/src/libpcp_qwt/src/qwt_math.cpp
new file mode 100644
index 0000000..06a039a
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_math.cpp
@@ -0,0 +1,45 @@
+/* -*- 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;
+}
diff --git a/src/libpcp_qwt/src/qwt_math.h b/src/libpcp_qwt/src/qwt_math.h
new file mode 100644
index 0000000..fa8a476
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_math.h
@@ -0,0 +1,182 @@
+/* -*- 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 <qpoint.h>
+#include <qmath.h>
+#include "qwt_global.h"
+
+#ifndef LOG10_2
+#define LOG10_2 0.30102999566398119802 /* log10(2) */
+#endif
+
+#ifndef LOG10_3
+#define LOG10_3 0.47712125471966243540 /* log10(3) */
+#endif
+
+#ifndef LOG10_5
+#define LOG10_5 0.69897000433601885749 /* log10(5) */
+#endif
+
+#ifndef M_2PI
+#define M_2PI 6.28318530717958623200 /* 2 pi */
+#endif
+
+#ifndef LOG_MIN
+//! Mininum 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
+
+#ifndef M_E
+#define M_E 2.7182818284590452354 /* e */
+#endif
+
+#ifndef M_LOG2E
+#define M_LOG2E 1.4426950408889634074 /* log_2 e */
+#endif
+
+#ifndef M_LOG10E
+#define M_LOG10E 0.43429448190325182765 /* log_10 e */
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942 /* log_e 2 */
+#endif
+
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402 /* log_e 10 */
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+
+#ifndef M_PI_4
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
+#endif
+
+#ifndef M_1_PI
+#define M_1_PI 0.31830988618379067154 /* 1/pi */
+#endif
+
+#ifndef M_2_PI
+#define M_2_PI 0.63661977236758134308 /* 2/pi */
+#endif
+
+#ifndef M_2_SQRTPI
+#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+#endif
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#endif
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+#endif
+
+QWT_EXPORT double qwtGetMin( const double *array, int size );
+QWT_EXPORT double qwtGetMax( const double *array, int size );
+
+/*!
+ \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;
+}
+
+//! Like qRound, but without converting the result to an int
+inline double qwtRoundF(double d)
+{
+ return ::floor( d + 0.5 );
+}
+
+//! Like qFloor, but without converting the result to an int
+inline double qwtFloorF(double d)
+{
+ return ::floor( d );
+}
+
+//! Like qCeil, but without converting the result to an int
+inline double qwtCeilF(double d)
+{
+ return ::ceil( d );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_matrix_raster_data.cpp b/src/libpcp_qwt/src/qwt_matrix_raster_data.cpp
new file mode 100644
index 0000000..2176ec9
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_matrix_raster_data.cpp
@@ -0,0 +1,270 @@
+/* -*- 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(size_t row, size_t col) const
+ {
+ return values.data()[ row * numColumns + col ];
+ }
+
+ QwtMatrixRasterData::ResampleMode resampleMode;
+
+ QVector<double> values;
+ size_t numColumns;
+ size_t 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, size_t numColumns )
+{
+ d_data->values = values;
+ d_data->numColumns = numColumns;
+ update();
+}
+
+/*!
+ \return Value matrix
+ \sa setValueMatrix(), numColumns(), numRows(), setInterval()
+*/
+const QVector<double> QwtMatrixRasterData::valueMatrix() const
+{
+ return d_data->values;
+}
+
+/*!
+ \return Number of columns of the value matrix
+ \sa valueMatrix(), numRows(), setValueMatrix()
+*/
+size_t QwtMatrixRasterData::numColumns() const
+{
+ return d_data->numColumns;
+}
+
+/*!
+ \return Number of rows of the value matrix
+ \sa valueMatrix(), numColumns(), setValueMatrix()
+*/
+size_t QwtMatrixRasterData::numRows() const
+{
+ return d_data->numRows;
+}
+
+/*!
+ \brief Pixel hint
+
+ - 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.
+
+ \sa ResampleMode, setMatrix(), setInterval()
+*/
+QRectF QwtMatrixRasterData::pixelHint( const QRectF & ) const
+{
+ 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 >= (int)d_data->numColumns )
+ col2 = col1;
+
+ if ( row1 < 0 )
+ row1 = row2;
+ else if ( row2 >= (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:
+ {
+ uint row = uint( (y - yInterval.minValue() ) / d_data->dy );
+ uint col = uint( (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;
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_matrix_raster_data.h b/src/libpcp_qwt/src/qwt_matrix_raster_data.h
new file mode 100644
index 0000000..a8940f8
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_matrix_raster_data.h
@@ -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_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, size_t numColumns );
+
+ const QVector<double> valueMatrix() const;
+ size_t numColumns() const;
+ size_t 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
diff --git a/src/libpcp_qwt/src/qwt_null_paintdevice.cpp b/src/libpcp_qwt/src/qwt_null_paintdevice.cpp
new file mode 100644
index 0000000..cdab2a6
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_null_paintdevice.cpp
@@ -0,0 +1,428 @@
+/* -*- 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_null_paintdevice.h"
+#include <qpaintengine.h>
+#include <qpixmap.h>
+
+class QwtNullPaintDevice::PrivateData
+{
+public:
+ PrivateData():
+ size( 0, 0 )
+ {
+ }
+
+ QSize size;
+};
+
+class QwtNullPaintDevice::PaintEngine: public QPaintEngine
+{
+public:
+ PaintEngine( QPaintEngine::PaintEngineFeatures );
+
+ virtual bool begin( QPaintDevice * );
+ virtual bool end();
+
+ virtual Type type () const;
+ virtual void updateState(const QPaintEngineState &);
+
+ 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 , PolygonDrawMode );
+ virtual void drawPolygon(const QPoint *, int , 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 &s);
+ virtual void drawImage(const QRectF &,
+ const QImage &, const QRectF &, Qt::ImageConversionFlags );
+
+private:
+ QwtNullPaintDevice *d_device;
+};
+
+QwtNullPaintDevice::PaintEngine::PaintEngine(
+ QPaintEngine::PaintEngineFeatures features ):
+ QPaintEngine( features ),
+ d_device(NULL)
+{
+}
+
+bool QwtNullPaintDevice::PaintEngine::begin(
+ QPaintDevice *device )
+{
+ d_device = static_cast<QwtNullPaintDevice *>( device );
+ return true;
+}
+
+bool QwtNullPaintDevice::PaintEngine::end()
+{
+ d_device = NULL;
+ return true;
+}
+
+QPaintEngine::Type
+QwtNullPaintDevice::PaintEngine::type () const
+{
+ return QPaintEngine::User;
+}
+
+void QwtNullPaintDevice::PaintEngine::drawRects(
+ const QRect *rects, int rectCount)
+{
+ if ( d_device )
+ d_device->drawRects( rects, rectCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawRects(
+ const QRectF *rects, int rectCount)
+{
+ if ( d_device )
+ d_device->drawRects( rects, rectCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawLines(
+ const QLine *lines, int lineCount)
+{
+ if ( d_device )
+ d_device->drawLines( lines, lineCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawLines(
+ const QLineF *lines, int lineCount)
+{
+ if ( d_device )
+ d_device->drawLines( lines, lineCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawEllipse(
+ const QRectF &rect)
+{
+ if ( d_device )
+ d_device->drawEllipse( rect );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawEllipse(
+ const QRect &rect)
+{
+ if ( d_device )
+ d_device->drawEllipse( rect );
+}
+
+
+void QwtNullPaintDevice::PaintEngine::drawPath(
+ const QPainterPath &path)
+{
+ if ( d_device )
+ d_device->drawPath( path );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawPoints(
+ const QPointF *points, int pointCount)
+{
+ if ( d_device )
+ d_device->drawPoints( points, pointCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawPoints(
+ const QPoint *points, int pointCount)
+{
+ if ( d_device )
+ d_device->drawPoints( points, pointCount );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawPolygon(
+ const QPointF *points, int pointCount, PolygonDrawMode mode)
+{
+ if ( d_device )
+ d_device->drawPolygon( points, pointCount, mode );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawPolygon(
+ const QPoint *points, int pointCount, PolygonDrawMode mode)
+{
+ if ( d_device )
+ d_device->drawPolygon( points, pointCount, mode );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawPixmap(
+ const QRectF &rect, const QPixmap &pm, const QRectF &subRect )
+{
+ if ( d_device )
+ d_device->drawPixmap( rect, pm, subRect );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawTextItem(
+ const QPointF &pos, const QTextItem &textItem)
+{
+ if ( d_device )
+ d_device->drawTextItem( pos, textItem );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawTiledPixmap(
+ const QRectF &rect, const QPixmap &pixmap,
+ const QPointF &subRect)
+{
+ if ( d_device )
+ d_device->drawTiledPixmap( rect, pixmap, subRect );
+}
+
+void QwtNullPaintDevice::PaintEngine::drawImage(
+ const QRectF &rect, const QImage &image,
+ const QRectF &subRect, Qt::ImageConversionFlags flags)
+{
+ if ( d_device )
+ d_device->drawImage( rect, image, subRect, flags );
+}
+
+void QwtNullPaintDevice::PaintEngine::updateState(
+ const QPaintEngineState &state)
+{
+ if ( d_device )
+ d_device->updateState( state );
+}
+
+//! Constructor
+QwtNullPaintDevice::QwtNullPaintDevice(
+ QPaintEngine::PaintEngineFeatures features )
+{
+ init( features );
+}
+
+//! Constructor
+QwtNullPaintDevice::QwtNullPaintDevice( const QSize &size,
+ QPaintEngine::PaintEngineFeatures features )
+{
+ init( features );
+ d_data->size = size;
+}
+
+void QwtNullPaintDevice::init(
+ QPaintEngine::PaintEngineFeatures features )
+{
+ d_engine = new PaintEngine( features );
+ d_data = new PrivateData;
+}
+
+//! Destructor
+QwtNullPaintDevice::~QwtNullPaintDevice()
+{
+ delete d_engine;
+ delete d_data;
+}
+
+/*!
+ Set the size of the paint device
+
+ \param size Size
+ \sa size()
+*/
+void QwtNullPaintDevice::setSize( const QSize & size )
+{
+ d_data->size = size;
+}
+
+/*!
+ \return Size of the paint device
+ \sa setSize()
+*/
+QSize QwtNullPaintDevice::size() const
+{
+ return d_data->size;
+}
+
+//! See QPaintDevice::paintEngine()
+QPaintEngine *QwtNullPaintDevice::paintEngine() const
+{
+ return d_engine;
+}
+
+/*!
+ See QPaintDevice::metric()
+ \sa setSize()
+*/
+int QwtNullPaintDevice::metric( PaintDeviceMetric metric ) const
+{
+ static QPixmap pm;
+
+ int value;
+
+ switch ( metric )
+ {
+ case PdmWidth:
+ value = qMax( d_data->size.width(), 0 );
+ break;
+ case PdmHeight:
+ value = qMax( d_data->size.height(), 0 );
+ break;
+ case PdmNumColors:
+ value = 16777216;
+ break;
+ case PdmDepth:
+ value = 24;
+ break;
+ case PdmPhysicalDpiX:
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ case PdmWidthMM:
+ case PdmHeightMM:
+ case PdmDpiX:
+ default:
+ value = 0;
+ }
+ return value;
+
+}
+
+//! See QPaintEngine::drawRects()
+void QwtNullPaintDevice::drawRects(
+ const QRect *rects, int rectCount)
+{
+ Q_UNUSED(rects);
+ Q_UNUSED(rectCount);
+}
+
+//! See QPaintEngine::drawRects()
+void QwtNullPaintDevice::drawRects(
+ const QRectF *rects, int rectCount)
+{
+ Q_UNUSED(rects);
+ Q_UNUSED(rectCount);
+}
+
+//! See QPaintEngine::drawLines()
+void QwtNullPaintDevice::drawLines(
+ const QLine *lines, int lineCount)
+{
+ Q_UNUSED(lines);
+ Q_UNUSED(lineCount);
+}
+
+//! See QPaintEngine::drawLines()
+void QwtNullPaintDevice::drawLines(
+ const QLineF *lines, int lineCount)
+{
+ Q_UNUSED(lines);
+ Q_UNUSED(lineCount);
+}
+
+//! See QPaintEngine::drawEllipse()
+void QwtNullPaintDevice::drawEllipse( const QRectF &rect )
+{
+ Q_UNUSED(rect);
+}
+
+//! See QPaintEngine::drawEllipse()
+void QwtNullPaintDevice::drawEllipse( const QRect &rect )
+{
+ Q_UNUSED(rect);
+}
+
+//! See QPaintEngine::drawPath()
+void QwtNullPaintDevice::drawPath( const QPainterPath &path )
+{
+ Q_UNUSED(path);
+}
+
+//! See QPaintEngine::drawPoints()
+void QwtNullPaintDevice::drawPoints(
+ const QPointF *points, int pointCount)
+{
+ Q_UNUSED(points);
+ Q_UNUSED(pointCount);
+}
+
+//! See QPaintEngine::drawPoints()
+void QwtNullPaintDevice::drawPoints(
+ const QPoint *points, int pointCount)
+{
+ Q_UNUSED(points);
+ Q_UNUSED(pointCount);
+}
+
+//! See QPaintEngine::drawPolygon()
+void QwtNullPaintDevice::drawPolygon(
+ const QPointF *points, int pointCount,
+ QPaintEngine::PolygonDrawMode mode)
+{
+ Q_UNUSED(points);
+ Q_UNUSED(pointCount);
+ Q_UNUSED(mode);
+}
+
+//! See QPaintEngine::drawPolygon()
+void QwtNullPaintDevice::drawPolygon(
+ const QPoint *points, int pointCount,
+ QPaintEngine::PolygonDrawMode mode)
+{
+ Q_UNUSED(points);
+ Q_UNUSED(pointCount);
+ Q_UNUSED(mode);
+}
+
+//! See QPaintEngine::drawPixmap()
+void QwtNullPaintDevice::drawPixmap( const QRectF &rect,
+ const QPixmap &pm, const QRectF &subRect )
+{
+ Q_UNUSED(rect);
+ Q_UNUSED(pm);
+ Q_UNUSED(subRect);
+}
+
+//! See QPaintEngine::drawTextItem()
+void QwtNullPaintDevice::drawTextItem(
+ const QPointF &pos, const QTextItem &textItem)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(textItem);
+}
+
+//! See QPaintEngine::drawTiledPixmap()
+void QwtNullPaintDevice::drawTiledPixmap(
+ const QRectF &rect, const QPixmap &pixmap,
+ const QPointF &subRect)
+{
+ Q_UNUSED(rect);
+ Q_UNUSED(pixmap);
+ Q_UNUSED(subRect);
+}
+
+//! See QPaintEngine::drawImage()
+void QwtNullPaintDevice::drawImage(
+ const QRectF &rect, const QImage &image,
+ const QRectF &subRect, Qt::ImageConversionFlags flags)
+{
+ Q_UNUSED(rect);
+ Q_UNUSED(image);
+ Q_UNUSED(subRect);
+ Q_UNUSED(flags);
+}
+
+//! See QPaintEngine::updateState()
+void QwtNullPaintDevice::updateState(
+ const QPaintEngineState &state )
+{
+ Q_UNUSED(state);
+}
diff --git a/src/libpcp_qwt/src/qwt_null_paintdevice.h b/src/libpcp_qwt/src/qwt_null_paintdevice.h
new file mode 100644
index 0000000..aae9c2d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_null_paintdevice.h
@@ -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_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 changable from the public Qt class interface.
+ ( f.e hidden in the style implementation ).
+
+ QwtNullPaintDevice can be used to manipulate or filter out
+ these informations 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:
+ QwtNullPaintDevice( QPaintEngine::PaintEngineFeatures );
+ QwtNullPaintDevice( const QSize &size,
+ QPaintEngine::PaintEngineFeatures );
+
+ virtual ~QwtNullPaintDevice();
+
+ void setSize( const QSize &);
+ QSize size() const;
+
+ virtual QPaintEngine *paintEngine() const;
+ virtual int metric( PaintDeviceMetric metric ) 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 &s);
+
+ virtual void drawImage(const QRectF &,
+ const QImage &, const QRectF &, Qt::ImageConversionFlags );
+
+ virtual void updateState( const QPaintEngineState &state );
+
+private:
+ void init( QPaintEngine::PaintEngineFeatures );
+
+ class PaintEngine;
+ PaintEngine *d_engine;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_painter.cpp b/src/libpcp_qwt/src/qwt_painter.cpp
new file mode 100644
index 0000000..adc0859
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_painter.cpp
@@ -0,0 +1,765 @@
+/* -*- 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.h"
+#include "qwt_math.h"
+#include "qwt_clipper.h"
+#include "qwt_color_map.h"
+#include "qwt_scale_map.h"
+#include <qwindowdefs.h>
+#include <qwidget.h>
+#include <qframe.h>
+#include <qrect.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qpaintdevice.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qtextdocument.h>
+#include <qabstracttextdocumentlayout.h>
+#include <qstyleoption.h>
+#include <qpaintengine.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+
+bool QwtPainter::d_polylineSplitting = true;
+bool QwtPainter::d_roundingAlignment = true;
+
+static inline bool isClippingNeeded( const QPainter *painter, QRectF &clipRect )
+{
+ bool doClipping = false;
+ const QPaintEngine *pe = painter->paintEngine();
+ if ( pe && pe->type() == QPaintEngine::SVG )
+ {
+ // The SVG paint engine ignores any clipping,
+
+ if ( painter->hasClipping() )
+ {
+ doClipping = true;
+ clipRect = painter->clipRegion().boundingRect();
+ }
+ }
+
+ return doClipping;
+}
+
+static inline void drawPolyline( QPainter *painter,
+ const QPointF *points, int pointCount, bool polylineSplitting )
+{
+ bool doSplit = false;
+ if ( polylineSplitting )
+ {
+ const QPaintEngine *pe = painter->paintEngine();
+ if ( pe && pe->type() == QPaintEngine::Raster )
+ {
+ /*
+ The raster paint engine seems to use some algo with O(n*n).
+ ( Qt 4.3 is better than Qt 4.2, but remains unacceptable)
+ To work around this problem, we have to split the polygon into
+ smaller pieces.
+ */
+ doSplit = true;
+ }
+ }
+
+ if ( doSplit )
+ {
+ const int splitSize = 20;
+ for ( int i = 0; i < pointCount; i += splitSize )
+ {
+ const int n = qMin( splitSize + 1, pointCount - i );
+ painter->drawPolyline( points + i, n );
+ }
+ }
+ else
+ painter->drawPolyline( points, pointCount );
+}
+
+static inline void unscaleFont( QPainter *painter )
+{
+ if ( painter->font().pixelSize() >= 0 )
+ return;
+
+ static QSize screenResolution;
+ if ( !screenResolution.isValid() )
+ {
+ QDesktopWidget *desktop = QApplication::desktop();
+ if ( desktop )
+ {
+ screenResolution.setWidth( desktop->logicalDpiX() );
+ screenResolution.setHeight( desktop->logicalDpiY() );
+ }
+ }
+
+ const QPaintDevice *pd = painter->device();
+ if ( pd->logicalDpiX() != screenResolution.width() ||
+ pd->logicalDpiY() != screenResolution.height() )
+ {
+ QFont pixelFont( painter->font(), QApplication::desktop() );
+ pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
+
+ painter->setFont( pixelFont );
+ }
+}
+
+/*!
+ Check if the painter is using a paint engine, that aligns
+ coordinates to integers. Today these are all paint engines
+ beside QPaintEngine::Pdf and QPaintEngine::SVG.
+
+ \param painter Painter
+ \return true, when the paint engine is aligning
+
+ \sa setRoundingAlignment()
+*/
+bool QwtPainter::isAligning( QPainter *painter )
+{
+ if ( painter && painter->isActive() )
+ {
+ switch ( painter->paintEngine()->type() )
+ {
+ case QPaintEngine::Pdf:
+ case QPaintEngine::SVG:
+ return false;
+
+ default:;
+ }
+ }
+
+ return true;
+}
+
+/*!
+ Enable whether coordinates should be rounded, before they are painted
+ to a paint engine that floors to integer values. For other paint engines
+ this ( Pdf, SVG ), this flag has no effect.
+ QwtPainter stores this flag only, the rounding itsself is done in
+ the painting code ( f.e the plot items ).
+
+ The default setting is true.
+
+ \sa roundingAlignment(), isAligning()
+*/
+void QwtPainter::setRoundingAlignment( bool enable )
+{
+ d_roundingAlignment = enable;
+}
+
+/*!
+ \brief En/Disable line splitting for the raster paint engine
+
+ The raster paint engine paints polylines of many points
+ much faster when they are splitted in smaller chunks.
+
+ \sa polylineSplitting()
+*/
+void QwtPainter::setPolylineSplitting( bool enable )
+{
+ d_polylineSplitting = enable;
+}
+
+//! Wrapper for QPainter::drawPath()
+void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path )
+{
+ painter->drawPath( path );
+}
+
+//! Wrapper for QPainter::drawRect()
+void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h )
+{
+ drawRect( painter, QRectF( x, y, w, h ) );
+}
+
+//! Wrapper for QPainter::drawRect()
+void QwtPainter::drawRect( QPainter *painter, const QRectF &rect )
+{
+ const QRectF r = rect;
+
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping )
+ {
+ if ( !clipRect.intersects( r ) )
+ return;
+
+ if ( !clipRect.contains( r ) )
+ {
+ fillRect( painter, r & clipRect, painter->brush() );
+
+ painter->save();
+ painter->setBrush( Qt::NoBrush );
+ drawPolyline( painter, QPolygonF( r ) );
+ painter->restore();
+
+ return;
+ }
+ }
+
+ painter->drawRect( r );
+}
+
+//! Wrapper for QPainter::fillRect()
+void QwtPainter::fillRect( QPainter *painter,
+ const QRectF &rect, const QBrush &brush )
+{
+ if ( !rect.isValid() )
+ return;
+
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ /*
+ Performance of Qt4 is horrible for non trivial brushs. Without
+ clipping expect minutes or hours for repainting large rects
+ (might result from zooming)
+ */
+
+ if ( deviceClipping )
+ clipRect &= painter->window();
+ else
+ clipRect = painter->window();
+
+ if ( painter->hasClipping() )
+ clipRect &= painter->clipRegion().boundingRect();
+
+ QRectF r = rect;
+ if ( deviceClipping )
+ r = r.intersect( clipRect );
+
+ if ( r.isValid() )
+ painter->fillRect( r, brush );
+}
+
+//! Wrapper for QPainter::drawPie()
+void QwtPainter::drawPie( QPainter *painter, const QRectF &rect,
+ int a, int alen )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+ if ( deviceClipping && !clipRect.contains( rect ) )
+ return;
+
+ painter->drawPie( rect, a, alen );
+}
+
+//! Wrapper for QPainter::drawEllipse()
+void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping && !clipRect.contains( rect ) )
+ return;
+
+ painter->drawEllipse( rect );
+}
+
+//! Wrapper for QPainter::drawText()
+void QwtPainter::drawText( QPainter *painter, double x, double y,
+ const QString &text )
+{
+ drawText( painter, QPointF( x, y ), text );
+}
+
+//! Wrapper for QPainter::drawText()
+void QwtPainter::drawText( QPainter *painter, const QPointF &pos,
+ const QString &text )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping && !clipRect.contains( pos ) )
+ return;
+
+
+ painter->save();
+ unscaleFont( painter );
+ painter->drawText( pos, text );
+ painter->restore();
+}
+
+//! Wrapper for QPainter::drawText()
+void QwtPainter::drawText( QPainter *painter,
+ double x, double y, double w, double h,
+ int flags, const QString &text )
+{
+ drawText( painter, QRectF( x, y, w, h ), flags, text );
+}
+
+//! Wrapper for QPainter::drawText()
+void QwtPainter::drawText( QPainter *painter, const QRectF &rect,
+ int flags, const QString &text )
+{
+ painter->save();
+ unscaleFont( painter );
+ painter->drawText( rect, flags, text );
+ painter->restore();
+}
+
+#ifndef QT_NO_RICHTEXT
+
+/*!
+ Draw a text document into a rectangle
+
+ \param painter Painter
+ \param rect Traget rectangle
+ \param flags Alignments/Text flags, see QPainter::drawText()
+ \param text Text document
+*/
+void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
+ int flags, const QTextDocument &text )
+{
+ QTextDocument *txt = text.clone();
+
+ painter->save();
+
+ painter->setFont( txt->defaultFont() );
+ unscaleFont( painter );
+
+ txt->setDefaultFont( painter->font() );
+ txt->setPageSize( QSizeF( rect.width(), QWIDGETSIZE_MAX ) );
+
+ QAbstractTextDocumentLayout* layout = txt->documentLayout();
+
+ const double height = layout->documentSize().height();
+ double y = rect.y();
+ if ( flags & Qt::AlignBottom )
+ y += ( rect.height() - height );
+ else if ( flags & Qt::AlignVCenter )
+ y += ( rect.height() - height ) / 2;
+
+ QAbstractTextDocumentLayout::PaintContext context;
+ context.palette.setColor( QPalette::Text, painter->pen().color() );
+
+ painter->translate( rect.x(), y );
+ layout->draw( painter, context );
+
+ painter->restore();
+ delete txt;
+}
+
+#endif // !QT_NO_RICHTEXT
+
+
+//! Wrapper for QPainter::drawLine()
+void QwtPainter::drawLine( QPainter *painter,
+ const QPointF &p1, const QPointF &p2 )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping &&
+ !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
+ {
+ QPolygonF polygon;
+ polygon += p1;
+ polygon += p2;
+ drawPolyline( painter, polygon );
+ return;
+ }
+
+ painter->drawLine( p1, p2 );
+}
+
+//! Wrapper for QPainter::drawPolygon()
+void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ QPolygonF cpa = polygon;
+ if ( deviceClipping )
+ cpa = QwtClipper::clipPolygonF( clipRect, polygon );
+
+ painter->drawPolygon( cpa );
+}
+
+//! Wrapper for QPainter::drawPolyline()
+void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ QPolygonF cpa = polygon;
+ if ( deviceClipping )
+ cpa = QwtClipper::clipPolygonF( clipRect, cpa );
+
+ ::drawPolyline( painter,
+ cpa.constData(), cpa.size(), d_polylineSplitting );
+}
+
+//! Wrapper for QPainter::drawPolyline()
+void QwtPainter::drawPolyline( QPainter *painter,
+ const QPointF *points, int pointCount )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping )
+ {
+ QPolygonF polygon( pointCount );
+ qMemCopy( polygon.data(), points, pointCount * sizeof( QPointF ) );
+
+ polygon = QwtClipper::clipPolygonF( clipRect, polygon );
+ ::drawPolyline( painter,
+ polygon.constData(), polygon.size(), d_polylineSplitting );
+ }
+ else
+ ::drawPolyline( painter, points, pointCount, d_polylineSplitting );
+}
+
+//! Wrapper for QPainter::drawPoint()
+void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
+{
+ QRectF clipRect;
+ const bool deviceClipping = isClippingNeeded( painter, clipRect );
+
+ if ( deviceClipping && !clipRect.contains( pos ) )
+ return;
+
+ painter->drawPoint( pos );
+}
+
+//! Wrapper for QPainter::drawImage()
+void QwtPainter::drawImage( QPainter *painter,
+ const QRectF &rect, const QImage &image )
+{
+ const QRect alignedRect = rect.toAlignedRect();
+
+ if ( alignedRect != rect )
+ {
+ const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
+
+ painter->save();
+ painter->setClipRect( clipRect, Qt::IntersectClip );
+ painter->drawImage( alignedRect, image );
+ painter->restore();
+ }
+ else
+ {
+ painter->drawImage( alignedRect, image );
+ }
+}
+
+//! Wrapper for QPainter::drawPixmap()
+void QwtPainter::drawPixmap( QPainter *painter,
+ const QRectF &rect, const QPixmap &pixmap )
+{
+ const QRect alignedRect = rect.toAlignedRect();
+
+ if ( alignedRect != rect )
+ {
+ const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
+
+ painter->save();
+ painter->setClipRect( clipRect, Qt::IntersectClip );
+ painter->drawPixmap( alignedRect, pixmap );
+ painter->restore();
+ }
+ else
+ {
+ painter->drawPixmap( alignedRect, pixmap );
+ }
+}
+
+//! Draw a focus rectangle on a widget using its style.
+void QwtPainter::drawFocusRect( QPainter *painter, QWidget *widget )
+{
+ drawFocusRect( painter, widget, widget->rect() );
+}
+
+//! Draw a focus rectangle on a widget using its style.
+void QwtPainter::drawFocusRect( QPainter *painter, QWidget *widget,
+ const QRect &rect )
+{
+ QStyleOptionFocusRect opt;
+ opt.init( widget );
+ opt.rect = rect;
+ opt.state |= QStyle::State_HasFocus;
+
+ widget->style()->drawPrimitive( QStyle::PE_FrameFocusRect,
+ &opt, painter, widget );
+}
+
+/*!
+ Draw a frame with rounded borders
+
+ \param painter Painter
+ \param rect Frame rectangle
+ \param xRadius x-radius of the ellipses defining the corners
+ \param yRadius y-radius of the ellipses defining the corners
+ \param palette QPalette::WindowText is used for plain borders
+ QPalette::Dark and QPalette::Light for raised
+ or sunken borders
+ \param lineWidth Line width
+ \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
+*/
+
+void QwtPainter::drawRoundedFrame( QPainter *painter,
+ const QRectF &rect, double xRadius, double yRadius,
+ const QPalette &palette, int lineWidth, int frameStyle )
+{
+ painter->save();
+ painter->setRenderHint( QPainter::Antialiasing, true );
+ painter->setBrush( Qt::NoBrush );
+
+ double lw2 = lineWidth * 0.5;
+ QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
+
+ QPainterPath path;
+ path.addRoundedRect( r, xRadius, yRadius );
+
+ enum Style
+ {
+ Plain,
+ Sunken,
+ Raised
+ };
+
+ Style style = Plain;
+ if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
+ style = Sunken;
+ else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
+ style = Raised;
+
+ if ( style != Plain && path.elementCount() == 17 )
+ {
+ // move + 4 * ( cubicTo + lineTo )
+ QPainterPath pathList[8];
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ const int j = i * 4 + 1;
+
+ pathList[ 2 * i ].moveTo(
+ path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
+ );
+
+ pathList[ 2 * i ].cubicTo(
+ path.elementAt(j + 0).x, path.elementAt(j + 0).y,
+ path.elementAt(j + 1).x, path.elementAt(j + 1).y,
+ path.elementAt(j + 2).x, path.elementAt(j + 2).y );
+
+ pathList[ 2 * i + 1 ].moveTo(
+ path.elementAt(j + 2).x, path.elementAt(j + 2).y
+ );
+ pathList[ 2 * i + 1 ].lineTo(
+ path.elementAt(j + 3).x, path.elementAt(j + 3).y
+ );
+ }
+
+ QColor c1( palette.color( QPalette::Dark ) );
+ QColor c2( palette.color( QPalette::Light ) );
+
+ if ( style == Raised )
+ qSwap( c1, c2 );
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ QRectF r = pathList[2 * i].controlPointRect();
+
+ QPen arcPen;
+ arcPen.setWidth( lineWidth );
+
+ QPen linePen;
+ linePen.setWidth( lineWidth );
+
+ switch( i )
+ {
+ case 0:
+ {
+ arcPen.setColor( c1 );
+ linePen.setColor( c1 );
+ break;
+ }
+ case 1:
+ {
+ QLinearGradient gradient;
+ gradient.setStart( r.topLeft() );
+ gradient.setFinalStop( r.bottomRight() );
+ gradient.setColorAt( 0.0, c1 );
+ gradient.setColorAt( 1.0, c2 );
+
+ arcPen.setBrush( gradient );
+ linePen.setColor( c2 );
+ break;
+ }
+ case 2:
+ {
+ arcPen.setColor( c2 );
+ linePen.setColor( c2 );
+ break;
+ }
+ case 3:
+ {
+ QLinearGradient gradient;
+
+ gradient.setStart( r.bottomRight() );
+ gradient.setFinalStop( r.topLeft() );
+ gradient.setColorAt( 0.0, c2 );
+ gradient.setColorAt( 1.0, c1 );
+
+ arcPen.setBrush( gradient );
+ linePen.setColor( c1 );
+ break;
+ }
+ }
+
+
+ painter->setPen( arcPen );
+ painter->drawPath( pathList[ 2 * i] );
+
+ painter->setPen( linePen );
+ painter->drawPath( pathList[ 2 * i + 1] );
+ }
+ }
+ else
+ {
+ QPen pen( palette.color( QPalette::WindowText ), lineWidth );
+ painter->setPen( pen );
+ painter->drawPath( path );
+ }
+
+ painter->restore();
+}
+
+/*!
+ Draw a color bar into a rectangle
+
+ \param painter Painter
+ \param colorMap Color map
+ \param interval Value range
+ \param scaleMap Scale map
+ \param orientation Orientation
+ \param rect Traget rectangle
+*/
+void QwtPainter::drawColorBar( QPainter *painter,
+ const QwtColorMap &colorMap, const QwtInterval &interval,
+ const QwtScaleMap &scaleMap, Qt::Orientation orientation,
+ const QRectF &rect )
+{
+ QVector<QRgb> colorTable;
+ if ( colorMap.format() == QwtColorMap::Indexed )
+ colorTable = colorMap.colorTable( interval );
+
+ QColor c;
+
+ const QRect devRect = rect.toAlignedRect();
+
+ /*
+ We paint to a pixmap first to have something scalable for printing
+ ( f.e. in a Pdf document )
+ */
+
+ QPixmap pixmap( devRect.size() );
+ QPainter pmPainter( &pixmap );
+ pmPainter.translate( -devRect.x(), -devRect.y() );
+
+ if ( orientation == Qt::Horizontal )
+ {
+ QwtScaleMap sMap = scaleMap;
+ sMap.setPaintInterval( rect.left(), rect.right() );
+
+ for ( int x = devRect.left(); x <= devRect.right(); x++ )
+ {
+ const double value = sMap.invTransform( x );
+
+ if ( colorMap.format() == QwtColorMap::RGB )
+ c.setRgb( colorMap.rgb( interval, value ) );
+ else
+ c = colorTable[colorMap.colorIndex( interval, value )];
+
+ pmPainter.setPen( c );
+ pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
+ }
+ }
+ else // Vertical
+ {
+ QwtScaleMap sMap = scaleMap;
+ sMap.setPaintInterval( rect.bottom(), rect.top() );
+
+ for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
+ {
+ const double value = sMap.invTransform( y );
+
+ if ( colorMap.format() == QwtColorMap::RGB )
+ c.setRgb( colorMap.rgb( interval, value ) );
+ else
+ c = colorTable[colorMap.colorIndex( interval, value )];
+
+ pmPainter.setPen( c );
+ pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
+ }
+ }
+ pmPainter.end();
+
+ drawPixmap( painter, rect, pixmap );
+}
+
+#if QT_VERSION >= 0x050000
+
+static inline void qwtFillRect(QPainter *painter, const QRect &rect, const QBrush &brush)
+{
+ if ( brush.style() == Qt::TexturePattern )
+ {
+ painter->setClipRect( rect );
+ painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
+ }
+ else if (brush.gradient()
+ && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode)
+ {
+ painter->save();
+ painter->setClipRect( rect );
+ painter->fillRect(0, 0, painter->device()->width(),
+ painter->device()->height(), brush);
+ painter->restore();
+ }
+ else
+ {
+ painter->fillRect(rect, brush);
+ }
+}
+
+void QwtPainter::fillPixmap( const QWidget *widget,
+ QPixmap &pixmap, const QPoint &offset )
+{
+ // Qwt 5.0.0 Alpha offers an empty dummy implementation
+ // of QPixmap::fill, that does nothing helpful beside converting
+ // a compiler into a runtime error
+
+ const QRect rect( offset, pixmap.size() );
+
+ QPainter painter( &pixmap );
+ painter.translate( -offset );
+
+ const QBrush autoFillBrush =
+ widget->palette().brush( widget->backgroundRole() );
+
+ if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) )
+ {
+ const QBrush bg = widget->palette().brush( QPalette::Window );
+ qwtFillRect( &painter, rect, bg);
+ }
+
+ if ( widget->autoFillBackground() )
+ qwtFillRect( &painter, rect, autoFillBrush);
+
+ if ( widget->testAttribute(Qt::WA_StyledBackground) )
+ {
+ painter.setClipRegion( rect );
+
+ QStyleOption opt;
+ opt.initFrom( widget );
+ widget->style()->drawPrimitive( QStyle::PE_Widget,
+ &opt, &painter, widget );
+ }
+}
+
+#endif // QT_VERSION >= 0x050000
diff --git a/src/libpcp_qwt/src/qwt_painter.h b/src/libpcp_qwt/src/qwt_painter.h
new file mode 100644
index 0000000..3235099
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_painter.h
@@ -0,0 +1,154 @@
+/* -*- 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>
+
+class QPainter;
+class QBrush;
+class QColor;
+class QWidget;
+class QPolygonF;
+class QRectF;
+class QImage;
+class QPixmap;
+class QwtScaleMap;
+class QwtColorMap;
+class QwtInterval;
+
+class QPalette;
+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 & r, 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 &pa );
+ static void drawPolyline( QPainter *, const QPolygonF &pa );
+ static void drawPolyline( QPainter *, const QPointF *, int pointCount );
+
+ static void drawPoint( QPainter *, double x, double y );
+ static void drawPoint( QPainter *, const QPointF & );
+
+ static void drawPath( QPainter *, const QPainterPath & );
+ static void drawImage( QPainter *, const QRectF &, const QImage & );
+ static void drawPixmap( QPainter *, const QRectF &, const QPixmap & );
+
+ static void drawRoundedFrame( QPainter *,
+ const QRectF &, double xRadius, double yRadius,
+ const QPalette &, int lineWidth, int frameStyle );
+
+ static void drawFocusRect( QPainter *, QWidget * );
+ static void drawFocusRect( QPainter *, QWidget *, const QRect & );
+
+ static void drawColorBar( QPainter *painter,
+ const QwtColorMap &, const QwtInterval &,
+ const QwtScaleMap &, Qt::Orientation, const QRectF & );
+
+ static bool isAligning( QPainter *painter );
+
+#if QT_VERSION >= 0x050000
+ static void fillPixmap( const QWidget *,
+ QPixmap &, const QPoint &offset = QPoint() );
+#endif
+
+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::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() );
+}
+
+/*!
+ Returns whether line splitting for the raster paint engine is enabled.
+ \sa setPolylineSplitting()
+*/
+inline bool QwtPainter::polylineSplitting()
+{
+ return d_polylineSplitting;
+}
+
+/*!
+ Returns whether coordinates should be rounded, before they are painted
+ to a paint engine that floors to integer values. For other paint engines
+ this ( Pdf, SVG ), this flag has no effect.
+
+ \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
diff --git a/src/libpcp_qwt/src/qwt_panner.cpp b/src/libpcp_qwt/src/qwt_panner.cpp
new file mode 100644
index 0000000..709a2ea
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_panner.cpp
@@ -0,0 +1,537 @@
+/* -*- 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"
+#if QT_VERSION >= 0x050000
+#include "qwt_painter.h"
+#endif
+#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 ),
+ buttonState( Qt::NoButton ),
+ abortKey( Qt::Key_Escape ),
+ abortKeyState( Qt::NoButton ),
+#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
+ }
+
+ int button;
+ int buttonState;
+ int abortKey;
+ int abortKeyState;
+
+ 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
+ The defaults are Qt::LeftButton and Qt::NoButton
+*/
+void QwtPanner::setMouseButton( int button, int buttonState )
+{
+ d_data->button = button;
+ d_data->buttonState = buttonState;
+}
+
+//! Get the mouse button
+void QwtPanner::getMouseButton( int &button, int &buttonState ) const
+{
+ button = d_data->button;
+ buttonState = d_data->buttonState;
+}
+
+/*!
+ Change the abort key
+ The defaults are Qt::Key_Escape and Qt::NoButton
+
+ \param key Key ( See Qt::Keycode )
+ \param state State
+*/
+void QwtPanner::setAbortKey( int key, int state )
+{
+ d_data->abortKey = key;
+ d_data->abortKeyState = state;
+}
+
+//! Get the abort key
+void QwtPanner::getAbortKey( int &key, int &state ) const
+{
+ key = d_data->abortKey;
+ state = d_data->abortKeyState;
+}
+
+/*!
+ 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 a orientatio 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 pe Paint event
+*/
+void QwtPanner::paintEvent( QPaintEvent *pe )
+{
+ int dx = d_data->pos.x() - d_data->initialPos.x();
+ int dy = d_data->pos.y() - d_data->initialPos.y();
+
+ QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() );
+ r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) );
+
+ QPixmap pm( size() );
+#if QT_VERSION >= 0x050000
+ QwtPainter::fillPixmap( parentWidget(), pm );
+#else
+ pm.fill( parentWidget(), 0, 0 );
+#endif
+
+ QPainter painter( &pm );
+
+ if ( !d_data->contentsMask.isNull() )
+ {
+ QPixmap masked = d_data->pixmap;
+ masked.setMask( d_data->contentsMask );
+ painter.drawPixmap( r, masked );
+ }
+ else
+ {
+ painter.drawPixmap( r, d_data->pixmap );
+ }
+
+ painter.end();
+
+ if ( !d_data->contentsMask.isNull() )
+ pm.setMask( d_data->contentsMask );
+
+ painter.begin( this );
+ painter.setClipRegion( pe->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.
+*/
+QPixmap QwtPanner::grab() const
+{
+ return QPixmap::grabWidget( parentWidget() );
+}
+
+/*!
+ \brief Event filter
+
+ When isEnabled() the mouse events of the observed widget are filtered.
+
+ \param object Object to be filtered
+ \param event Event
+
+ \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( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseMove:
+ {
+ widgetMouseMoveEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ widgetMouseReleaseEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ widgetKeyPressEvent( ( QKeyEvent * )event );
+ break;
+ }
+ case QEvent::KeyRelease:
+ {
+ widgetKeyReleaseEvent( ( 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 )
+ return;
+
+ QWidget *w = parentWidget();
+ if ( w == NULL )
+ return;
+
+ if ( ( mouseEvent->modifiers() & Qt::KeyboardModifierMask ) !=
+ ( int )( d_data->buttonState & Qt::KeyboardModifierMask ) )
+ {
+ 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 )
+ {
+ const bool matched =
+ ( keyEvent->modifiers() & Qt::KeyboardModifierMask ) ==
+ ( int )( d_data->abortKeyState & Qt::KeyboardModifierMask );
+ if ( matched )
+ {
+ 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
diff --git a/src/libpcp_qwt/src/qwt_panner.h b/src/libpcp_qwt/src/qwt_panner.h
new file mode 100644
index 0000000..247d4a3
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_panner.h
@@ -0,0 +1,100 @@
+/* -*- 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_PANNER_H
+#define QWT_PANNER_H 1
+
+#include "qwt_global.h"
+#include <qwidget.h>
+#include <qpixmap.h>
+
+class QCursor;
+
+/*!
+ \brief QwtPanner provides panning of a widget
+
+ QwtPanner grabs the contents of a widget, that can be dragged
+ in all directions. The offset between the start and the end position
+ is emitted by the panned signal.
+
+ QwtPanner grabs the content of the widget into a pixmap and moves
+ the pixmap around, without initiating any repaint events for the widget.
+ Areas, that are not part of content are not painted while panning.
+ This makes panning fast enough for widgets, where
+ repaints are too slow for mouse movements.
+
+ For widgets, where repaints are very fast it might be better to
+ implement panning manually by mapping mouse events into paint events.
+*/
+class QWT_EXPORT QwtPanner: public QWidget
+{
+ Q_OBJECT
+
+public:
+ QwtPanner( QWidget* parent );
+ virtual ~QwtPanner();
+
+ void setEnabled( bool );
+ bool isEnabled() const;
+
+ void setMouseButton( int button, int buttonState = Qt::NoButton );
+ void getMouseButton( int &button, int &buttonState ) const;
+ void setAbortKey( int key, int state = Qt::NoButton );
+ void getAbortKey( int &key, int &state ) const;
+
+ void setCursor( const QCursor & );
+ const QCursor cursor() const;
+
+ void setOrientations( Qt::Orientations );
+ Qt::Orientations orientations() const;
+
+ bool isOrientationEnabled( Qt::Orientation ) const;
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+Q_SIGNALS:
+ /*!
+ Signal emitted, when panning is done
+
+ \param dx Offset in horizontal direction
+ \param dy Offset in vertical direction
+ */
+ void panned( int dx, int dy );
+
+ /*!
+ Signal emitted, while the widget moved, but panning
+ is not finished.
+
+ \param dx Offset in horizontal direction
+ \param dy Offset in vertical direction
+ */
+ void moved( int dx, int dy );
+
+protected:
+ virtual void widgetMousePressEvent( QMouseEvent * );
+ virtual void widgetMouseReleaseEvent( QMouseEvent * );
+ virtual void widgetMouseMoveEvent( QMouseEvent * );
+ virtual void widgetKeyPressEvent( QKeyEvent * );
+ virtual void widgetKeyReleaseEvent( QKeyEvent * );
+
+ virtual void paintEvent( QPaintEvent * );
+
+ virtual QBitmap contentsMask() const;
+ virtual QPixmap grab() const;
+
+private:
+#ifndef QT_NO_CURSOR
+ void showCursor( bool );
+#endif
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_picker.cpp b/src/libpcp_qwt/src/qwt_picker.cpp
new file mode 100644
index 0000000..2b7afa1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_picker.cpp
@@ -0,0 +1,1462 @@
+/* -*- 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_picker.h"
+#include "qwt_picker_machine.h"
+#include "qwt_painter.h"
+#include "qwt_math.h"
+#include <qapplication.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qframe.h>
+#include <qcursor.h>
+#include <qbitmap.h>
+#include <qpointer.h>
+#include <qpaintengine.h>
+#include <qmath.h>
+
+class QwtPicker::PickerWidget: public QWidget
+{
+public:
+ enum Type
+ {
+ RubberBand,
+ Text
+ };
+
+ PickerWidget( QwtPicker *, QWidget *, Type );
+ void updateMask();
+
+ /*
+ For a tracker text with a background we can use the background
+ rect as mask. Also for "regular" Qt widgets >= 4.3.0 we
+ don't need to mask the text anymore.
+ */
+ bool d_hasTextMask;
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ QwtPicker *d_picker;
+ Type d_type;
+};
+
+class QwtPicker::PrivateData
+{
+public:
+ bool enabled;
+
+ QwtPickerMachine *stateMachine;
+
+ QwtPicker::ResizeMode resizeMode;
+
+ QwtPicker::RubberBand rubberBand;
+ QPen rubberBandPen;
+
+ QwtPicker::DisplayMode trackerMode;
+ QPen trackerPen;
+ QFont trackerFont;
+
+ QPolygon pickedPoints;
+ bool isActive;
+ QPoint trackerPosition;
+
+ bool mouseTracking; // used to save previous value
+
+ /*
+ On X11 the widget below the picker widgets gets paint events
+ with a region that is the bounding rect of the mask, if it is complex.
+ In case of (f.e) a CrossRubberBand and a text this creates complete
+ repaints of the widget. So we better use two different widgets.
+ */
+
+ QPointer<PickerWidget> rubberBandWidget;
+ QPointer<PickerWidget> trackerWidget;
+};
+
+QwtPicker::PickerWidget::PickerWidget(
+ QwtPicker *picker, QWidget *parent, Type type ):
+ QWidget( parent ),
+ d_hasTextMask( false ),
+ d_picker( picker ),
+ d_type( type )
+{
+ setAttribute( Qt::WA_TransparentForMouseEvents );
+ setAttribute( Qt::WA_NoSystemBackground );
+ setFocusPolicy( Qt::NoFocus );
+}
+
+void QwtPicker::PickerWidget::updateMask()
+{
+ QRegion mask;
+
+ if ( d_type == RubberBand )
+ {
+ QBitmap bm( width(), height() );
+ bm.fill( Qt::color0 );
+
+ QPainter painter( &bm );
+ QPen pen = d_picker->rubberBandPen();
+ pen.setColor( Qt::color1 );
+ painter.setPen( pen );
+
+ d_picker->drawRubberBand( &painter );
+
+ mask = QRegion( bm );
+ }
+ if ( d_type == Text )
+ {
+ d_hasTextMask = parentWidget()->testAttribute( Qt::WA_PaintOnScreen );
+
+ if ( d_hasTextMask )
+ {
+ const QwtText label = d_picker->trackerText(
+ d_picker->trackerPosition() );
+
+ if ( label.testPaintAttribute( QwtText::PaintBackground )
+ && label.backgroundBrush().style() != Qt::NoBrush )
+ {
+ if ( label.backgroundBrush().color().alpha() > 0 )
+ {
+ // We don't need a text mask, when we have a background
+ d_hasTextMask = false;
+ }
+ }
+ }
+
+ if ( d_hasTextMask )
+ {
+ QBitmap bm( width(), height() );
+ bm.fill( Qt::color0 );
+
+ QPainter painter( &bm );
+ painter.setFont( font() );
+
+ QPen pen = d_picker->trackerPen();
+ pen.setColor( Qt::color1 );
+ painter.setPen( pen );
+
+ d_picker->drawTracker( &painter );
+
+ mask = QRegion( bm );
+ }
+ else
+ {
+ mask = d_picker->trackerRect( font() );
+ }
+ }
+
+ QWidget *w = parentWidget();
+ if ( w && !w->testAttribute( Qt::WA_PaintOnScreen ) )
+ {
+ // The parent widget gets an update for its complete rectangle
+ // when the mask is changed in visible state.
+ // With this hide/show we only get an update for the
+ // previous mask.
+
+ hide();
+ }
+ setMask( mask );
+ setVisible( !mask.isEmpty() );
+}
+
+void QwtPicker::PickerWidget::paintEvent( QPaintEvent *e )
+{
+ QPainter painter( this );
+ painter.setClipRegion( e->region() );
+
+ if ( d_type == RubberBand )
+ {
+ painter.setPen( d_picker->rubberBandPen() );
+ d_picker->drawRubberBand( &painter );
+ }
+
+ if ( d_type == Text )
+ {
+ /*
+ If we have a text mask we simply fill the region of
+ the mask. This gives better results for antialiased fonts.
+ */
+ if ( d_hasTextMask )
+ {
+ painter.fillRect( e->rect(),
+ QBrush( d_picker->trackerPen().color() ) );
+ }
+ else
+ {
+ painter.setPen( d_picker->trackerPen() );
+ d_picker->drawTracker( &painter );
+ }
+ }
+}
+
+void QwtPicker::PickerWidget::resizeEvent( QResizeEvent *event )
+{
+ QWidget::resizeEvent( event );
+ if ( isVisible() )
+ updateMask();
+}
+
+/*!
+ Constructor
+
+ Creates an picker that is enabled, but without a state machine.
+ rubberband and tracker are disabled.
+
+ \param parent Parent widget, that will be observed
+ */
+
+QwtPicker::QwtPicker( QWidget *parent ):
+ QObject( parent )
+{
+ init( parent, NoRubberBand, AlwaysOff );
+}
+
+/*!
+ Constructor
+
+ \param rubberBand Rubberband style
+ \param trackerMode Tracker mode
+ \param parent Parent widget, that will be observed
+ */
+QwtPicker::QwtPicker( RubberBand rubberBand,
+ DisplayMode trackerMode, QWidget *parent ):
+ QObject( parent )
+{
+ init( parent, rubberBand, trackerMode );
+}
+
+//! Destructor
+QwtPicker::~QwtPicker()
+{
+ setMouseTracking( false );
+ delete d_data->stateMachine;
+ delete d_data->rubberBandWidget;
+ delete d_data->trackerWidget;
+ delete d_data;
+}
+
+//! Init the picker, used by the constructors
+void QwtPicker::init( QWidget *parent,
+ RubberBand rubberBand, DisplayMode trackerMode )
+{
+ d_data = new PrivateData;
+
+ d_data->rubberBandWidget = NULL;
+ d_data->trackerWidget = NULL;
+
+ d_data->rubberBand = rubberBand;
+ d_data->enabled = false;
+ d_data->resizeMode = Stretch;
+ d_data->trackerMode = AlwaysOff;
+ d_data->isActive = false;
+ d_data->trackerPosition = QPoint( -1, -1 );
+ d_data->mouseTracking = false;
+
+ d_data->stateMachine = NULL;
+
+ if ( parent )
+ {
+ if ( parent->focusPolicy() == Qt::NoFocus )
+ parent->setFocusPolicy( Qt::WheelFocus );
+
+ d_data->trackerFont = parent->font();
+ d_data->mouseTracking = parent->hasMouseTracking();
+ setEnabled( true );
+ }
+ setTrackerMode( trackerMode );
+}
+
+/*!
+ Set a state machine and delete the previous one
+
+ \param stateMachine State machine
+ \sa stateMachine()
+*/
+void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine )
+{
+ if ( d_data->stateMachine != stateMachine )
+ {
+ reset();
+
+ delete d_data->stateMachine;
+ d_data->stateMachine = stateMachine;
+
+ if ( d_data->stateMachine )
+ d_data->stateMachine->reset();
+ }
+}
+
+/*!
+ \return Assigned state machine
+ \sa setStateMachine()
+*/
+QwtPickerMachine *QwtPicker::stateMachine()
+{
+ return d_data->stateMachine;
+}
+
+/*!
+ \return Assigned state machine
+ \sa setStateMachine()
+*/
+const QwtPickerMachine *QwtPicker::stateMachine() const
+{
+ return d_data->stateMachine;
+}
+
+//! Return the parent widget, where the selection happens
+QWidget *QwtPicker::parentWidget()
+{
+ QObject *obj = parent();
+ if ( obj && obj->isWidgetType() )
+ return static_cast<QWidget *>( obj );
+
+ return NULL;
+}
+
+//! Return the parent widget, where the selection happens
+const QWidget *QwtPicker::parentWidget() const
+{
+ QObject *obj = parent();
+ if ( obj && obj->isWidgetType() )
+ return static_cast< const QWidget *>( obj );
+
+ return NULL;
+}
+
+/*!
+ Set the rubberband style
+
+ \param rubberBand Rubberband style
+ The default value is NoRubberBand.
+
+ \sa rubberBand(), RubberBand, setRubberBandPen()
+*/
+void QwtPicker::setRubberBand( RubberBand rubberBand )
+{
+ d_data->rubberBand = rubberBand;
+}
+
+/*!
+ \return Rubberband style
+ \sa setRubberBand(), RubberBand, rubberBandPen()
+*/
+QwtPicker::RubberBand QwtPicker::rubberBand() const
+{
+ return d_data->rubberBand;
+}
+
+/*!
+ \brief Set the display mode of the tracker.
+
+ A tracker displays information about current position of
+ the cursor as a string. The display mode controls
+ if the tracker has to be displayed whenever the observed
+ widget has focus and cursor (AlwaysOn), never (AlwaysOff), or
+ only when the selection is active (ActiveOnly).
+
+ \param mode Tracker display mode
+
+ \warning In case of AlwaysOn, mouseTracking will be enabled
+ for the observed widget.
+ \sa trackerMode(), DisplayMode
+*/
+
+void QwtPicker::setTrackerMode( DisplayMode mode )
+{
+ if ( d_data->trackerMode != mode )
+ {
+ d_data->trackerMode = mode;
+ setMouseTracking( d_data->trackerMode == AlwaysOn );
+ }
+}
+
+/*!
+ \return Tracker display mode
+ \sa setTrackerMode(), DisplayMode
+*/
+QwtPicker::DisplayMode QwtPicker::trackerMode() const
+{
+ return d_data->trackerMode;
+}
+
+/*!
+ \brief Set the resize mode.
+
+ The resize mode controls what to do with the selected points of an active
+ selection when the observed widget is resized.
+
+ Stretch means the points are scaled according to the new
+ size, KeepSize means the points remain unchanged.
+
+ The default mode is Stretch.
+
+ \param mode Resize mode
+ \sa resizeMode(), ResizeMode
+*/
+void QwtPicker::setResizeMode( ResizeMode mode )
+{
+ d_data->resizeMode = mode;
+}
+
+/*!
+ \return Resize mode
+ \sa setResizeMode(), ResizeMode
+*/
+
+QwtPicker::ResizeMode QwtPicker::resizeMode() const
+{
+ return d_data->resizeMode;
+}
+
+/*!
+ \brief En/disable the picker
+
+ When enabled is true an event filter is installed for
+ the observed widget, otherwise the event filter is removed.
+
+ \param enabled true or false
+ \sa isEnabled(), eventFilter()
+*/
+void QwtPicker::setEnabled( bool enabled )
+{
+ if ( d_data->enabled != enabled )
+ {
+ d_data->enabled = enabled;
+
+ QWidget *w = parentWidget();
+ if ( w )
+ {
+ if ( enabled )
+ w->installEventFilter( this );
+ else
+ w->removeEventFilter( this );
+ }
+
+ updateDisplay();
+ }
+}
+
+/*!
+ \return true when enabled, false otherwise
+ \sa setEnabled(), eventFilter()
+*/
+
+bool QwtPicker::isEnabled() const
+{
+ return d_data->enabled;
+}
+
+/*!
+ Set the font for the tracker
+
+ \param font Tracker font
+ \sa trackerFont(), setTrackerMode(), setTrackerPen()
+*/
+void QwtPicker::setTrackerFont( const QFont &font )
+{
+ if ( font != d_data->trackerFont )
+ {
+ d_data->trackerFont = font;
+ updateDisplay();
+ }
+}
+
+/*!
+ \return Tracker font
+ \sa setTrackerFont(), trackerMode(), trackerPen()
+*/
+
+QFont QwtPicker::trackerFont() const
+{
+ return d_data->trackerFont;
+}
+
+/*!
+ Set the pen for the tracker
+
+ \param pen Tracker pen
+ \sa trackerPen(), setTrackerMode(), setTrackerFont()
+*/
+void QwtPicker::setTrackerPen( const QPen &pen )
+{
+ if ( pen != d_data->trackerPen )
+ {
+ d_data->trackerPen = pen;
+ updateDisplay();
+ }
+}
+
+/*!
+ \return Tracker pen
+ \sa setTrackerPen(), trackerMode(), trackerFont()
+*/
+QPen QwtPicker::trackerPen() const
+{
+ return d_data->trackerPen;
+}
+
+/*!
+ Set the pen for the rubberband
+
+ \param pen Rubberband pen
+ \sa rubberBandPen(), setRubberBand()
+*/
+void QwtPicker::setRubberBandPen( const QPen &pen )
+{
+ if ( pen != d_data->rubberBandPen )
+ {
+ d_data->rubberBandPen = pen;
+ updateDisplay();
+ }
+}
+
+/*!
+ \return Rubberband pen
+ \sa setRubberBandPen(), rubberBand()
+*/
+QPen QwtPicker::rubberBandPen() const
+{
+ return d_data->rubberBandPen;
+}
+
+/*!
+ \brief Return the label for a position
+
+ In case of HLineRubberBand the label is the value of the
+ y position, in case of VLineRubberBand the value of the x position.
+ Otherwise the label contains x and y position separated by a ',' .
+
+ The format for the string conversion is "%d".
+
+ \param pos Position
+ \return Converted position as string
+*/
+
+QwtText QwtPicker::trackerText( const QPoint &pos ) const
+{
+ QString label;
+
+ switch ( rubberBand() )
+ {
+ case HLineRubberBand:
+ label.sprintf( "%d", pos.y() );
+ break;
+ case VLineRubberBand:
+ label.sprintf( "%d", pos.x() );
+ break;
+ default:
+ label.sprintf( "%d, %d", pos.x(), pos.y() );
+ }
+ return label;
+}
+
+/*!
+ Draw a rubberband, depending on rubberBand()
+
+ \param painter Painter, initialized with clip rect
+
+ \sa rubberBand(), RubberBand
+*/
+
+void QwtPicker::drawRubberBand( QPainter *painter ) const
+{
+ if ( !isActive() || rubberBand() == NoRubberBand ||
+ rubberBandPen().style() == Qt::NoPen )
+ {
+ return;
+ }
+
+ const QRect &pRect = pickRect();
+ const QPolygon pa = adjustedPoints( d_data->pickedPoints );
+
+ QwtPickerMachine::SelectionType selectionType =
+ QwtPickerMachine::NoSelection;
+
+ if ( d_data->stateMachine )
+ selectionType = d_data->stateMachine->selectionType();
+
+ switch ( selectionType )
+ {
+ case QwtPickerMachine::NoSelection:
+ case QwtPickerMachine::PointSelection:
+ {
+ if ( pa.count() < 1 )
+ return;
+
+ const QPoint pos = pa[0];
+
+ switch ( rubberBand() )
+ {
+ case VLineRubberBand:
+ QwtPainter::drawLine( painter, pos.x(),
+ pRect.top(), pos.x(), pRect.bottom() );
+ break;
+
+ case HLineRubberBand:
+ QwtPainter::drawLine( painter, pRect.left(),
+ pos.y(), pRect.right(), pos.y() );
+ break;
+
+ case CrossRubberBand:
+ QwtPainter::drawLine( painter, pos.x(),
+ pRect.top(), pos.x(), pRect.bottom() );
+ QwtPainter::drawLine( painter, pRect.left(),
+ pos.y(), pRect.right(), pos.y() );
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case QwtPickerMachine::RectSelection:
+ {
+ if ( pa.count() < 2 )
+ return;
+
+ const QPoint p1 = pa[0];
+ const QPoint p2 = pa[int( pa.count() - 1 )];
+
+ const QRect rect = QRect( p1, p2 ).normalized();
+ switch ( rubberBand() )
+ {
+ case EllipseRubberBand:
+ QwtPainter::drawEllipse( painter, rect );
+ break;
+ case RectRubberBand:
+ QwtPainter::drawRect( painter, rect );
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case QwtPickerMachine::PolygonSelection:
+ {
+ if ( rubberBand() == PolygonRubberBand )
+ painter->drawPolyline( pa );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*!
+ Draw the tracker
+
+ \param painter Painter
+ \sa trackerRect(), trackerText()
+*/
+
+void QwtPicker::drawTracker( QPainter *painter ) const
+{
+ const QRect textRect = trackerRect( painter->font() );
+ if ( !textRect.isEmpty() )
+ {
+ const QwtText label = trackerText( d_data->trackerPosition );
+ if ( !label.isEmpty() )
+ label.draw( painter, textRect );
+ }
+}
+
+/*!
+ \brief Map the pickedPoints() into a selection()
+
+ adjustedPoints() maps the points, that have been collected on
+ the parentWidget() into a selection(). The default implementation
+ simply returns the points unmodified.
+
+ The reason, why a selection() differs from the picked points
+ depends on the application requirements. F.e. :
+
+ - A rectangular selection might need to have a specific aspect ratio only.\n
+ - A selection could accept non intersecting polygons only.\n
+ - ...\n
+
+ The example below is for a rectangular selection, where the first
+ point is the center of the selected rectangle.
+ \par Example
+ \verbatim QPolygon MyPicker::adjustedPoints(const QPolygon &points) const
+{
+ QPolygon adjusted;
+ if ( points.size() == 2 )
+ {
+ const int width = qAbs(points[1].x() - points[0].x());
+ const int height = qAbs(points[1].y() - points[0].y());
+
+ QRect rect(0, 0, 2 * width, 2 * height);
+ rect.moveCenter(points[0]);
+
+ adjusted += rect.topLeft();
+ adjusted += rect.bottomRight();
+ }
+ return adjusted;
+}\endverbatim\n
+*/
+QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const
+{
+ return points;
+}
+
+/*!
+ \return Selected points
+ \sa pickedPoints(), adjustedPoints()
+*/
+QPolygon QwtPicker::selection() const
+{
+ return adjustedPoints( d_data->pickedPoints );
+}
+
+//! \return Current position of the tracker
+QPoint QwtPicker::trackerPosition() const
+{
+ return d_data->trackerPosition;
+}
+
+/*!
+ Calculate the bounding rectangle for the tracker text
+ from the current position of the tracker
+
+ \param font Font of the tracker text
+ \return Bounding rectangle of the tracker text
+
+ \sa trackerPosition()
+*/
+QRect QwtPicker::trackerRect( const QFont &font ) const
+{
+ if ( trackerMode() == AlwaysOff ||
+ ( trackerMode() == ActiveOnly && !isActive() ) )
+ {
+ return QRect();
+ }
+
+ if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
+ return QRect();
+
+ QwtText text = trackerText( d_data->trackerPosition );
+ if ( text.isEmpty() )
+ return QRect();
+
+ const QSizeF textSize = text.textSize( font );
+ QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) );
+
+ const QPoint &pos = d_data->trackerPosition;
+
+ int alignment = 0;
+ if ( isActive() && d_data->pickedPoints.count() > 1
+ && rubberBand() != NoRubberBand )
+ {
+ const QPoint last =
+ d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2];
+
+ alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft;
+ alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop;
+ }
+ else
+ alignment = Qt::AlignTop | Qt::AlignRight;
+
+ const int margin = 5;
+
+ int x = pos.x();
+ if ( alignment & Qt::AlignLeft )
+ x -= textRect.width() + margin;
+ else if ( alignment & Qt::AlignRight )
+ x += margin;
+
+ int y = pos.y();
+ if ( alignment & Qt::AlignBottom )
+ y += margin;
+ else if ( alignment & Qt::AlignTop )
+ y -= textRect.height() + margin;
+
+ textRect.moveTopLeft( QPoint( x, y ) );
+
+ int right = qMin( textRect.right(), pickRect().right() - margin );
+ int bottom = qMin( textRect.bottom(), pickRect().bottom() - margin );
+ textRect.moveBottomRight( QPoint( right, bottom ) );
+
+ int left = qMax( textRect.left(), pickRect().left() + margin );
+ int top = qMax( textRect.top(), pickRect().top() + margin );
+ textRect.moveTopLeft( QPoint( left, top ) );
+
+ return textRect;
+}
+
+/*!
+ \brief Event filter
+
+ When isEnabled() == true all events of the observed widget are filtered.
+ Mouse and keyboard events are translated into widgetMouse- and widgetKey-
+ and widgetWheel-events. Paint and Resize events are handled to keep
+ rubberband and tracker up to date.
+
+ \param object Object to be filtered
+ \param event Event
+
+ \sa widgetEnterEvent(), widgetLeaveEvent(),
+ widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent(),
+ QObject::installEventFilter(), QObject::event()
+*/
+bool QwtPicker::eventFilter( QObject *object, QEvent *event )
+{
+ if ( object && object == parentWidget() )
+ {
+ switch ( event->type() )
+ {
+ case QEvent::Resize:
+ {
+ const QResizeEvent *re = ( QResizeEvent * )event;
+ if ( d_data->resizeMode == Stretch )
+ stretchSelection( re->oldSize(), re->size() );
+
+ if ( d_data->rubberBandWidget )
+ d_data->rubberBandWidget->resize( re->size() );
+
+ if ( d_data->trackerWidget )
+ d_data->trackerWidget->resize( re->size() );
+ break;
+ }
+ case QEvent::Enter:
+ {
+ widgetEnterEvent( event );
+ break;
+ }
+ case QEvent::Leave:
+ {
+ widgetLeaveEvent( event );
+ break;
+ }
+ case QEvent::MouseButtonPress:
+ {
+ widgetMousePressEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ widgetMouseReleaseEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseButtonDblClick:
+ {
+ widgetMouseDoubleClickEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::MouseMove:
+ {
+ widgetMouseMoveEvent( ( QMouseEvent * )event );
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ widgetKeyPressEvent( ( QKeyEvent * )event );
+ break;
+ }
+ case QEvent::KeyRelease:
+ {
+ widgetKeyReleaseEvent( ( QKeyEvent * )event );
+ break;
+ }
+ case QEvent::Wheel:
+ {
+ widgetWheelEvent( ( QWheelEvent * )event );
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+/*!
+ Handle a mouse press event for the observed widget.
+
+ \param mouseEvent Mouse event
+
+ \sa eventFilter(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent )
+{
+ transition( mouseEvent );
+}
+
+/*!
+ Handle a mouse move event for the observed widget.
+
+ \param mouseEvent Mouse event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
+{
+ if ( pickRect().contains( mouseEvent->pos() ) )
+ d_data->trackerPosition = mouseEvent->pos();
+ else
+ d_data->trackerPosition = QPoint( -1, -1 );
+
+ if ( !isActive() )
+ updateDisplay();
+
+ transition( mouseEvent );
+}
+
+/*!
+ Handle a enter event for the observed widget.
+
+ \param event Qt event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetEnterEvent( QEvent *event )
+{
+ transition( event );
+}
+
+/*!
+ Handle a leave event for the observed widget.
+
+ \param event Qt event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetLeaveEvent( QEvent *event )
+{
+ transition( event );
+
+ d_data->trackerPosition = QPoint( -1, -1 );
+ if ( !isActive() )
+ updateDisplay();
+}
+
+/*!
+ Handle a mouse relase event for the observed widget.
+
+ \param mouseEvent Mouse event
+
+ \sa eventFilter(), widgetMousePressEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
+{
+ transition( mouseEvent );
+}
+
+/*!
+ Handle mouse double click event for the observed widget.
+
+ \param mouseEvent Mouse event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent )
+{
+ transition( mouseEvent );
+}
+
+
+/*!
+ Handle a wheel event for the observed widget.
+
+ Move the last point of the selection in case of isActive() == true
+
+ \param wheelEvent Wheel event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetKeyPressEvent(), widgetKeyReleaseEvent()
+*/
+void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent )
+{
+ if ( pickRect().contains( wheelEvent->pos() ) )
+ d_data->trackerPosition = wheelEvent->pos();
+ else
+ d_data->trackerPosition = QPoint( -1, -1 );
+
+ updateDisplay();
+
+ transition( wheelEvent );
+}
+
+/*!
+ Handle a key press event for the observed widget.
+
+ Selections can be completely done by the keyboard. The arrow keys
+ move the cursor, the abort key aborts a selection. All other keys
+ are handled by the current state machine.
+
+ \param keyEvent Key event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyReleaseEvent(), stateMachine(),
+ QwtEventPattern::KeyPatternCode
+*/
+void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent )
+{
+ int dx = 0;
+ int dy = 0;
+
+ int offset = 1;
+ if ( keyEvent->isAutoRepeat() )
+ offset = 5;
+
+ if ( keyMatch( KeyLeft, keyEvent ) )
+ dx = -offset;
+ else if ( keyMatch( KeyRight, keyEvent ) )
+ dx = offset;
+ else if ( keyMatch( KeyUp, keyEvent ) )
+ dy = -offset;
+ else if ( keyMatch( KeyDown, keyEvent ) )
+ dy = offset;
+ else if ( keyMatch( KeyAbort, keyEvent ) )
+ {
+ reset();
+ }
+ else
+ transition( keyEvent );
+
+ if ( dx != 0 || dy != 0 )
+ {
+ const QRect rect = pickRect();
+ const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() );
+
+ int x = pos.x() + dx;
+ x = qMax( rect.left(), x );
+ x = qMin( rect.right(), x );
+
+ int y = pos.y() + dy;
+ y = qMax( rect.top(), y );
+ y = qMin( rect.bottom(), y );
+
+ QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) );
+ }
+}
+
+/*!
+ Handle a key release event for the observed widget.
+
+ Passes the event to the state machine.
+
+ \param keyEvent Key event
+
+ \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
+ widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
+ widgetWheelEvent(), widgetKeyPressEvent(), stateMachine()
+*/
+void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
+{
+ transition( keyEvent );
+}
+
+/*!
+ Passes an event to the state machine and executes the resulting
+ commands. Append and Move commands use the current position
+ of the cursor (QCursor::pos()).
+
+ \param event Event
+*/
+void QwtPicker::transition( const QEvent *event )
+{
+ if ( !d_data->stateMachine )
+ return;
+
+ const QList<QwtPickerMachine::Command> commandList =
+ d_data->stateMachine->transition( *this, event );
+
+ QPoint pos;
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ {
+ const QMouseEvent *me =
+ static_cast< const QMouseEvent * >( event );
+ pos = me->pos();
+ break;
+ }
+ default:
+ pos = parentWidget()->mapFromGlobal( QCursor::pos() );
+ }
+
+ for ( int i = 0; i < commandList.count(); i++ )
+ {
+ switch ( commandList[i] )
+ {
+ case QwtPickerMachine::Begin:
+ {
+ begin();
+ break;
+ }
+ case QwtPickerMachine::Append:
+ {
+ append( pos );
+ break;
+ }
+ case QwtPickerMachine::Move:
+ {
+ move( pos );
+ break;
+ }
+ case QwtPickerMachine::Remove:
+ {
+ remove();
+ break;
+ }
+ case QwtPickerMachine::End:
+ {
+ end();
+ break;
+ }
+ }
+ }
+}
+
+/*!
+ Open a selection setting the state to active
+
+ \sa isActive(), end(), append(), move()
+*/
+void QwtPicker::begin()
+{
+ if ( d_data->isActive )
+ return;
+
+ d_data->pickedPoints.resize( 0 );
+ d_data->isActive = true;
+ Q_EMIT activated( true );
+
+ if ( trackerMode() != AlwaysOff )
+ {
+ if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
+ {
+ QWidget *w = parentWidget();
+ if ( w )
+ d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() );
+ }
+ }
+
+ updateDisplay();
+ setMouseTracking( true );
+}
+
+/*!
+ \brief Close a selection setting the state to inactive.
+
+ The selection is validated and maybe fixed by accept().
+
+ \param ok If true, complete the selection and emit a selected signal
+ otherwise discard the selection.
+ \return true if the selection is accepted, false otherwise
+ \sa isActive(), begin(), append(), move(), selected(), accept()
+*/
+bool QwtPicker::end( bool ok )
+{
+ if ( d_data->isActive )
+ {
+ setMouseTracking( false );
+
+ d_data->isActive = false;
+ Q_EMIT activated( false );
+
+ if ( trackerMode() == ActiveOnly )
+ d_data->trackerPosition = QPoint( -1, -1 );
+
+ if ( ok )
+ ok = accept( d_data->pickedPoints );
+
+ if ( ok )
+ Q_EMIT selected( d_data->pickedPoints );
+ else
+ d_data->pickedPoints.resize( 0 );
+
+ updateDisplay();
+ }
+ else
+ ok = false;
+
+ return ok;
+}
+
+/*!
+ Reset the state machine and terminate (end(false)) the selection
+*/
+void QwtPicker::reset()
+{
+ if ( d_data->stateMachine )
+ d_data->stateMachine->reset();
+
+ if ( isActive() )
+ end( false );
+}
+
+/*!
+ Append a point to the selection and update rubberband and tracker.
+ The appended() signal is emitted.
+
+ \param pos Additional point
+
+ \sa isActive(), begin(), end(), move(), appended()
+*/
+void QwtPicker::append( const QPoint &pos )
+{
+ if ( d_data->isActive )
+ {
+ const int idx = d_data->pickedPoints.count();
+ d_data->pickedPoints.resize( idx + 1 );
+ d_data->pickedPoints[idx] = pos;
+
+ updateDisplay();
+ Q_EMIT appended( pos );
+ }
+}
+
+/*!
+ Move the last point of the selection
+ The moved() signal is emitted.
+
+ \param pos New position
+ \sa isActive(), begin(), end(), append()
+*/
+void QwtPicker::move( const QPoint &pos )
+{
+ if ( d_data->isActive )
+ {
+ const int idx = d_data->pickedPoints.count() - 1;
+ if ( idx >= 0 )
+ {
+ if ( d_data->pickedPoints[idx] != pos )
+ {
+ d_data->pickedPoints[idx] = pos;
+
+ updateDisplay();
+ Q_EMIT moved( pos );
+ }
+ }
+ }
+}
+
+/*!
+ Remove the last point of the selection
+ The removed() signal is emitted.
+
+ \sa isActive(), begin(), end(), append(), move()
+*/
+void QwtPicker::remove()
+{
+ if ( d_data->isActive )
+ {
+ const int idx = d_data->pickedPoints.count() - 1;
+ if ( idx > 0 )
+ {
+ const int idx = d_data->pickedPoints.count();
+
+ const QPoint pos = d_data->pickedPoints[idx - 1];
+ d_data->pickedPoints.resize( idx - 1 );
+
+ updateDisplay();
+ Q_EMIT removed( pos );
+ }
+ }
+}
+
+/*!
+ \brief Validate and fixup the selection
+
+ Accepts all selections unmodified
+
+ \param selection Selection to validate and fixup
+ \return true, when accepted, false otherwise
+*/
+bool QwtPicker::accept( QPolygon &selection ) const
+{
+ Q_UNUSED( selection );
+ return true;
+}
+
+/*!
+ A picker is active between begin() and end().
+ \return true if the selection is active.
+*/
+bool QwtPicker::isActive() const
+{
+ return d_data->isActive;
+}
+
+/*!
+ Return the points, that have been collected so far. The selection()
+ is calculated from the pickedPoints() in adjustedPoints().
+ \return Picked points
+*/
+const QPolygon &QwtPicker::pickedPoints() const
+{
+ return d_data->pickedPoints;
+}
+
+/*!
+ Scale the selection by the ratios of oldSize and newSize
+ The changed() signal is emitted.
+
+ \param oldSize Previous size
+ \param newSize Current size
+
+ \sa ResizeMode, setResizeMode(), resizeMode()
+*/
+void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize )
+{
+ if ( oldSize.isEmpty() )
+ {
+ // avoid division by zero. But scaling for small sizes also
+ // doesn't make much sense, because of rounding losses. TODO ...
+ return;
+ }
+
+ const double xRatio =
+ double( newSize.width() ) / double( oldSize.width() );
+ const double yRatio =
+ double( newSize.height() ) / double( oldSize.height() );
+
+ for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ )
+ {
+ QPoint &p = d_data->pickedPoints[i];
+ p.setX( qRound( p.x() * xRatio ) );
+ p.setY( qRound( p.y() * yRatio ) );
+
+ Q_EMIT changed( d_data->pickedPoints );
+ }
+}
+
+/*!
+ Set mouse tracking for the observed widget.
+
+ In case of enable is true, the previous value
+ is saved, that is restored when enable is false.
+
+ \warning Even when enable is false, mouse tracking might be restored
+ to true. When mouseTracking for the observed widget
+ has been changed directly by QWidget::setMouseTracking
+ while mouse tracking has been set to true, this value can't
+ be restored.
+*/
+
+void QwtPicker::setMouseTracking( bool enable )
+{
+ QWidget *widget = parentWidget();
+ if ( !widget )
+ return;
+
+ if ( enable )
+ {
+ d_data->mouseTracking = widget->hasMouseTracking();
+ widget->setMouseTracking( true );
+ }
+ else
+ {
+ widget->setMouseTracking( d_data->mouseTracking );
+ }
+}
+
+/*!
+ Find the area of the observed widget, where selection might happen.
+
+ \return parentWidget()->contentsRect()
+*/
+QRect QwtPicker::pickRect() const
+{
+ const QWidget *widget = parentWidget();
+ if ( widget )
+ return widget->contentsRect();
+
+ return QRect();
+}
+
+//! Update the state of rubberband and tracker label
+void QwtPicker::updateDisplay()
+{
+ QWidget *w = parentWidget();
+
+ bool showRubberband = false;
+ bool showTracker = false;
+ if ( w && w->isVisible() && d_data->enabled )
+ {
+ if ( rubberBand() != NoRubberBand && isActive() &&
+ rubberBandPen().style() != Qt::NoPen )
+ {
+ showRubberband = true;
+ }
+
+ if ( trackerMode() == AlwaysOn ||
+ ( trackerMode() == ActiveOnly && isActive() ) )
+ {
+ if ( trackerPen() != Qt::NoPen )
+ showTracker = true;
+ }
+ }
+
+ QPointer<PickerWidget> &rw = d_data->rubberBandWidget;
+ if ( showRubberband )
+ {
+ if ( rw.isNull() )
+ {
+ rw = new PickerWidget( this, w, PickerWidget::RubberBand );
+ rw->setObjectName( "PickerRubberBand" );
+ rw->resize( w->size() );
+ }
+ rw->updateMask();
+ rw->update(); // Needed, when the mask doesn't change
+ }
+ else
+ delete rw;
+
+ QPointer<PickerWidget> &tw = d_data->trackerWidget;
+ if ( showTracker )
+ {
+ if ( tw.isNull() )
+ {
+ tw = new PickerWidget( this, w, PickerWidget::Text );
+ tw->setObjectName( "PickerTracker" );
+ tw->resize( w->size() );
+ }
+ tw->setFont( d_data->trackerFont );
+ tw->updateMask();
+ tw->update(); // Needed, when the mask doesn't change
+ }
+ else
+ delete tw;
+}
+
+//! \return Widget displaying the rubberband
+const QWidget *QwtPicker::rubberBandWidget() const
+{
+ return d_data->rubberBandWidget;
+}
+
+//! \return Widget displaying the tracker text
+const QWidget *QwtPicker::trackerWidget() const
+{
+ return d_data->trackerWidget;
+}
+
diff --git a/src/libpcp_qwt/src/qwt_picker.h b/src/libpcp_qwt/src/qwt_picker.h
new file mode 100644
index 0000000..c0b22dc
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_picker.h
@@ -0,0 +1,327 @@
+/* -*- 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_PICKER
+#define QWT_PICKER 1
+
+#include "qwt_global.h"
+#include "qwt_text.h"
+#include "qwt_event_pattern.h"
+#include <qobject.h>
+#include <qpen.h>
+#include <qfont.h>
+#include <qrect.h>
+
+class QWidget;
+class QMouseEvent;
+class QWheelEvent;
+class QKeyEvent;
+class QwtPickerMachine;
+
+/*!
+ \brief QwtPicker provides selections on a widget
+
+ QwtPicker filters all enter, leave, mouse and keyboard events of a widget
+ and translates them into an array of selected points.
+
+ The way how the points are collected depends on type of state machine
+ that is connected to the picker. Qwt offers a couple of predefined
+ state machines for selecting:
+
+ - Nothing\n
+ QwtPickerTrackerMachine
+ - Single points\n
+ QwtPickerClickPointMachine, QwtPickerDragPointMachine
+ - Rectangles\n
+ QwtPickerClickRectMachine, QwtPickerDragRectMachine
+ - Polygons\n
+ QwtPickerPolygonMachine
+
+ While these state machines cover the most common ways to collect points
+ it is also possible to implement individual machines as well.
+
+ QwtPicker translates the picked points into a selection using the
+ adjustedPoints method. adjustedPoints is intended to be reimplemented
+ to fixup the selection according to application specific requirements.
+ (F.e. when an application accepts rectangles of a fixed aspect ratio only.)
+
+ Optionally QwtPicker support the process of collecting points by a
+ rubberband and tracker displaying a text for the current mouse
+ position.
+
+ \par Example
+ \verbatim #include <qwt_picker.h>
+#include <qwt_picker_machine.h>
+
+QwtPicker *picker = new QwtPicker(widget);
+picker->setStateMachine(new QwtPickerDragRectMachine);
+picker->setTrackerMode(QwtPicker::ActiveOnly);
+picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n
+
+ The state machine triggers the following commands:
+
+ - begin()\n
+ Activate/Initialize the selection.
+ - append()\n
+ Add a new point
+ - move() \n
+ Change the position of the last point.
+ - remove()\n
+ Remove the last point.
+ - end()\n
+ Terminate the selection and call accept to validate the picked points.
+
+ The picker is active (isActive()), between begin() and end().
+ In active state the rubberband is displayed, and the tracker is visible
+ in case of trackerMode is ActiveOnly or AlwaysOn.
+
+ The cursor can be moved using the arrow keys. All selections can be aborted
+ using the abort key. (QwtEventPattern::KeyPatternCode)
+
+ \warning In case of QWidget::NoFocus the focus policy of the observed
+ widget is set to QWidget::WheelFocus and mouse tracking
+ will be manipulated while the picker is active,
+ or if trackerMode() is AlwayOn.
+*/
+
+class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern
+{
+ Q_OBJECT
+
+ Q_ENUMS( RubberBand )
+ Q_ENUMS( DisplayMode )
+ Q_ENUMS( ResizeMode )
+
+ Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled )
+ Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode )
+
+ Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode )
+ Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen )
+ Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont )
+
+ Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand )
+ Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen )
+
+public:
+ /*!
+ Rubberband style
+
+ The default value is QwtPicker::NoRubberBand.
+ \sa setRubberBand(), rubberBand()
+ */
+
+ enum RubberBand
+ {
+ //! No rubberband.
+ NoRubberBand = 0,
+
+ //! A horizontal line ( only for QwtPicker::PointSelection )
+ HLineRubberBand,
+
+ //! A vertical line ( only for QwtPicker::PointSelection )
+ VLineRubberBand,
+
+ //! A crosshair ( only for QwtPicker::PointSelection )
+ CrossRubberBand,
+
+ //! A rectangle ( only for QwtPicker::RectSelection )
+ RectRubberBand,
+
+ //! An ellipse ( only for QwtPicker::RectSelection )
+ EllipseRubberBand,
+
+ //! A polygon ( only for QwtPicker::&PolygonSelection )
+ PolygonRubberBand,
+
+ /*!
+ Values >= UserRubberBand can be used to define additional
+ rubber bands.
+ */
+ UserRubberBand = 100
+ };
+
+ /*!
+ \brief Display mode
+ \sa setTrackerMode(), trackerMode(), isActive()
+ */
+ enum DisplayMode
+ {
+ //! Display never
+ AlwaysOff,
+
+ //! Display always
+ AlwaysOn,
+
+ //! Display only when the selection is active
+ ActiveOnly
+ };
+
+ /*!
+ Controls what to do with the selected points of an active
+ selection when the observed widget is resized.
+
+ The default value is QwtPicker::Stretch.
+ \sa setResizeMode()
+ */
+
+ enum ResizeMode
+ {
+ //! All points are scaled according to the new size,
+ Stretch,
+
+ //! All points remain unchanged.
+ KeepSize
+ };
+
+ explicit QwtPicker( QWidget *parent );
+ explicit QwtPicker( RubberBand rubberBand,
+ DisplayMode trackerMode, QWidget * );
+
+ virtual ~QwtPicker();
+
+ void setStateMachine( QwtPickerMachine * );
+ const QwtPickerMachine *stateMachine() const;
+ QwtPickerMachine *stateMachine();
+
+ void setRubberBand( RubberBand );
+ RubberBand rubberBand() const;
+
+ void setTrackerMode( DisplayMode );
+ DisplayMode trackerMode() const;
+
+ void setResizeMode( ResizeMode );
+ ResizeMode resizeMode() const;
+
+ void setRubberBandPen( const QPen & );
+ QPen rubberBandPen() const;
+
+ void setTrackerPen( const QPen & );
+ QPen trackerPen() const;
+
+ void setTrackerFont( const QFont & );
+ QFont trackerFont() const;
+
+ bool isEnabled() const;
+ bool isActive() const;
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ QWidget *parentWidget();
+ const QWidget *parentWidget() const;
+
+ virtual QRect pickRect() const;
+
+ virtual void drawRubberBand( QPainter * ) const;
+ virtual void drawTracker( QPainter * ) const;
+
+ virtual QwtText trackerText( const QPoint &pos ) const;
+ QPoint trackerPosition() const;
+ virtual QRect trackerRect( const QFont & ) const;
+
+ QPolygon selection() const;
+
+public Q_SLOTS:
+ void setEnabled( bool );
+
+Q_SIGNALS:
+ /*!
+ A signal indicating, when the picker has been activated.
+ Together with setEnabled() it can be used to implement
+ selections with more than one picker.
+
+ \param on True, when the picker has been activated
+ */
+ void activated( bool on );
+
+ /*!
+ A signal emitting the selected points,
+ at the end of a selection.
+
+ \param polygon Selected points
+ */
+ void selected( const QPolygon &polygon );
+
+ /*!
+ A signal emitted when a point has been appended to the selection
+
+ \param pos Position of the appended point.
+ \sa append(). moved()
+ */
+ void appended( const QPoint &pos );
+
+ /*!
+ A signal emitted whenever the last appended point of the
+ selection has been moved.
+
+ \param pos Position of the moved last point of the selection.
+ \sa move(), appended()
+ */
+ void moved( const QPoint &pos );
+
+ /*!
+ A signal emitted whenever the last appended point of the
+ selection has been removed.
+
+ \sa remove(), appended()
+ */
+ void removed( const QPoint &pos );
+ /*!
+ A signal emitted when the active selection has been changed.
+ This might happen when the observed widget is resized.
+
+ \param selection Changed selection
+ \sa stretchSelection()
+ */
+ void changed( const QPolygon &selection );
+
+protected:
+ virtual QPolygon adjustedPoints( const QPolygon & ) const;
+
+ virtual void transition( const QEvent * );
+
+ virtual void begin();
+ virtual void append( const QPoint & );
+ virtual void move( const QPoint & );
+ virtual void remove();
+ virtual bool end( bool ok = true );
+
+ virtual bool accept( QPolygon & ) const;
+ virtual void reset();
+
+ virtual void widgetMousePressEvent( QMouseEvent * );
+ virtual void widgetMouseReleaseEvent( QMouseEvent * );
+ virtual void widgetMouseDoubleClickEvent( QMouseEvent * );
+ virtual void widgetMouseMoveEvent( QMouseEvent * );
+ virtual void widgetWheelEvent( QWheelEvent * );
+ virtual void widgetKeyPressEvent( QKeyEvent * );
+ virtual void widgetKeyReleaseEvent( QKeyEvent * );
+ virtual void widgetEnterEvent( QEvent * );
+ virtual void widgetLeaveEvent( QEvent * );
+
+ virtual void stretchSelection( const QSize &oldSize,
+ const QSize &newSize );
+
+ virtual void updateDisplay();
+
+ const QWidget *rubberBandWidget() const;
+ const QWidget *trackerWidget() const;
+
+ const QPolygon &pickedPoints() const;
+
+private:
+ void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode );
+
+ void setMouseTracking( bool );
+
+ class PickerWidget;
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_picker_machine.cpp b/src/libpcp_qwt/src/qwt_picker_machine.cpp
new file mode 100644
index 0000000..d43cc88
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_picker_machine.cpp
@@ -0,0 +1,455 @@
+/* -*- 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_picker_machine.h"
+#include "qwt_event_pattern.h"
+#include <qevent.h>
+
+//! Constructor
+QwtPickerMachine::QwtPickerMachine( SelectionType type ):
+ d_selectionType( type ),
+ d_state( 0 )
+{
+}
+
+//! Destructor
+QwtPickerMachine::~QwtPickerMachine()
+{
+}
+
+//! Return the selection type
+QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const
+{
+ return d_selectionType;
+}
+
+//! Return the current state
+int QwtPickerMachine::state() const
+{
+ return d_state;
+}
+
+//! Change the current state
+void QwtPickerMachine::setState( int state )
+{
+ d_state = state;
+}
+
+//! Set the current state to 0.
+void QwtPickerMachine::reset()
+{
+ setState( 0 );
+}
+
+//! Constructor
+QwtPickerTrackerMachine::QwtPickerTrackerMachine():
+ QwtPickerMachine( NoSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerTrackerMachine::transition(
+ const QwtEventPattern &, const QEvent *e )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( e->type() )
+ {
+ case QEvent::Enter:
+ case QEvent::MouseMove:
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ setState( 1 );
+ }
+ else
+ {
+ cmdList += Move;
+ }
+ break;
+ }
+ case QEvent::Leave:
+ {
+ cmdList += Remove;
+ cmdList += End;
+ setState( 0 );
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
+
+//! Constructor
+QwtPickerClickPointMachine::QwtPickerClickPointMachine():
+ QwtPickerMachine( PointSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerClickPointMachine::transition(
+ const QwtEventPattern &eventPattern, const QEvent *event )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonPress:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += End;
+ }
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += End;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
+
+//! Constructor
+QwtPickerDragPointMachine::QwtPickerDragPointMachine():
+ QwtPickerMachine( PointSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerDragPointMachine::transition(
+ const QwtEventPattern &eventPattern, const QEvent *event )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonPress:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ setState( 1 );
+ }
+ }
+ break;
+ }
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ {
+ if ( state() != 0 )
+ cmdList += Move;
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ if ( state() != 0 )
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ setState( 1 );
+ }
+ else
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
+
+//! Constructor
+QwtPickerClickRectMachine::QwtPickerClickRectMachine():
+ QwtPickerMachine( RectSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerClickRectMachine::transition(
+ const QwtEventPattern &eventPattern, const QEvent *event )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonPress:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ switch ( state() )
+ {
+ case 0:
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ setState( 1 );
+ break;
+ }
+ case 1:
+ {
+ // Uh, strange we missed the MouseButtonRelease
+ break;
+ }
+ default:
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ }
+ break;
+ }
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ {
+ if ( state() != 0 )
+ cmdList += Move;
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ if ( state() == 1 )
+ {
+ cmdList += Append;
+ setState( 2 );
+ }
+ }
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ setState( 1 );
+ }
+ else
+ {
+ if ( state() == 1 )
+ {
+ cmdList += Append;
+ setState( 2 );
+ }
+ else if ( state() == 2 )
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
+
+//! Constructor
+QwtPickerDragRectMachine::QwtPickerDragRectMachine():
+ QwtPickerMachine( RectSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerDragRectMachine::transition(
+ const QwtEventPattern &eventPattern, const QEvent *event )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonPress:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += Append;
+ setState( 2 );
+ }
+ }
+ break;
+ }
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ {
+ if ( state() != 0 )
+ cmdList += Move;
+ break;
+ }
+ case QEvent::MouseButtonRelease:
+ {
+ if ( state() == 2 )
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += Append;
+ setState( 2 );
+ }
+ else
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
+
+//! Constructor
+QwtPickerPolygonMachine::QwtPickerPolygonMachine():
+ QwtPickerMachine( PolygonSelection )
+{
+}
+
+//! Transition
+QList<QwtPickerMachine::Command> QwtPickerPolygonMachine::transition(
+ const QwtEventPattern &eventPattern, const QEvent *event )
+{
+ QList<QwtPickerMachine::Command> cmdList;
+
+ switch ( event->type() )
+ {
+ case QEvent::MouseButtonPress:
+ {
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect1, ( const QMouseEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += Append;
+ setState( 1 );
+ }
+ else
+ {
+ cmdList += Append;
+ }
+ }
+ if ( eventPattern.mouseMatch(
+ QwtEventPattern::MouseSelect2, ( const QMouseEvent * )event ) )
+ {
+ if ( state() == 1 )
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ break;
+ }
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ {
+ if ( state() != 0 )
+ cmdList += Move;
+ break;
+ }
+ case QEvent::KeyPress:
+ {
+ if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect1, ( const QKeyEvent * )event ) )
+ {
+ if ( state() == 0 )
+ {
+ cmdList += Begin;
+ cmdList += Append;
+ cmdList += Append;
+ setState( 1 );
+ }
+ else
+ {
+ cmdList += Append;
+ }
+ }
+ else if ( eventPattern.keyMatch(
+ QwtEventPattern::KeySelect2, ( const QKeyEvent * )event ) )
+ {
+ if ( state() == 1 )
+ {
+ cmdList += End;
+ setState( 0 );
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return cmdList;
+}
diff --git a/src/libpcp_qwt/src/qwt_picker_machine.h b/src/libpcp_qwt/src/qwt_picker_machine.h
new file mode 100644
index 0000000..8527115
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_picker_machine.h
@@ -0,0 +1,190 @@
+/* -*- 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_PICKER_MACHINE
+#define QWT_PICKER_MACHINE 1
+
+#include "qwt_global.h"
+#include <qlist.h>
+
+class QEvent;
+class QwtEventPattern;
+
+/*!
+ \brief A state machine for QwtPicker selections
+
+ QwtPickerMachine accepts key and mouse events and translates them
+ into selection commands.
+
+ \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
+*/
+
+class QWT_EXPORT QwtPickerMachine
+{
+public:
+ /*!
+ Type of a selection.
+ \sa selectionType()
+ */
+ enum SelectionType
+ {
+ //! The state machine not usable for any type of selection.
+ NoSelection = -1,
+
+ //! The state machine is for selecting a single point.
+ PointSelection,
+
+ //! The state machine is for selecting a rectangle (2 points).
+ RectSelection,
+
+ //! The state machine is for selecting a polygon (many points).
+ PolygonSelection
+ };
+
+ //! Commands - the output of a state machine
+ enum Command
+ {
+ Begin,
+ Append,
+ Move,
+ Remove,
+ End
+ };
+
+ QwtPickerMachine( SelectionType );
+ virtual ~QwtPickerMachine();
+
+ //! Transition
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * ) = 0;
+ void reset();
+
+ int state() const;
+ void setState( int );
+
+ SelectionType selectionType() const;
+
+private:
+ const SelectionType d_selectionType;
+ int d_state;
+};
+
+/*!
+ \brief A state machine for indicating mouse movements
+
+ QwtPickerTrackerMachine supports displaying information
+ corresponding to mouse movements, but is not intended for
+ selecting anything. Begin/End are related to Enter/Leave events.
+*/
+class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerTrackerMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+/*!
+ \brief A state machine for point selections
+
+ Pressing QwtEventPattern::MouseSelect1 or
+ QwtEventPattern::KeySelect1 selects a point.
+
+ \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
+*/
+class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerClickPointMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+/*!
+ \brief A state machine for point selections
+
+ Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
+ starts the selection, releasing QwtEventPattern::MouseSelect1 or
+ a second press of QwtEventPattern::KeySelect1 terminates it.
+*/
+class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerDragPointMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+/*!
+ \brief A state machine for rectangle selections
+
+ Pressing QwtEventPattern::MouseSelect1 starts
+ the selection, releasing it selects the first point. Pressing it
+ again selects the second point and terminates the selection.
+ Pressing QwtEventPattern::KeySelect1 also starts the
+ selection, a second press selects the first point. A third one selects
+ the second point and terminates the selection.
+
+ \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
+*/
+
+class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerClickRectMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+/*!
+ \brief A state machine for rectangle selections
+
+ Pressing QwtEventPattern::MouseSelect1 selects
+ the first point, releasing it the second point.
+ Pressing QwtEventPattern::KeySelect1 also selects the
+ first point, a second press selects the second point and terminates
+ the selection.
+
+ \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
+*/
+
+class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerDragRectMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+/*!
+ \brief A state machine for polygon selections
+
+ Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
+ starts the selection and selects the first point, or appends a point.
+ Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2
+ appends the last point and terminates the selection.
+
+ \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
+*/
+
+class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine
+{
+public:
+ QwtPickerPolygonMachine();
+
+ virtual QList<Command> transition(
+ const QwtEventPattern &, const QEvent * );
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot.cpp b/src/libpcp_qwt/src/qwt_plot.cpp
new file mode 100644
index 0000000..1e2fb3e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot.cpp
@@ -0,0 +1,751 @@
+/* -*- 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_plot.h"
+#include "qwt_plot_dict.h"
+#include "qwt_plot_layout.h"
+#include "qwt_scale_widget.h"
+#include "qwt_scale_engine.h"
+#include "qwt_text_label.h"
+#include "qwt_legend.h"
+#include "qwt_dyngrid_layout.h"
+#include "qwt_plot_canvas.h"
+#include <qpainter.h>
+#include <qpointer.h>
+#include <qpaintengine.h>
+#include <qapplication.h>
+#include <qevent.h>
+
+class QwtPlot::PrivateData
+{
+public:
+ QPointer<QwtTextLabel> titleLabel;
+ QPointer<QwtPlotCanvas> canvas;
+ QPointer<QwtLegend> legend;
+ QwtPlotLayout *layout;
+
+ bool autoReplot;
+};
+
+/*!
+ \brief Constructor
+ \param parent Parent widget
+ */
+QwtPlot::QwtPlot( QWidget *parent ):
+ QFrame( parent )
+{
+ initPlot( QwtText() );
+}
+
+/*!
+ \brief Constructor
+ \param title Title text
+ \param parent Parent widget
+ */
+QwtPlot::QwtPlot( const QwtText &title, QWidget *parent ):
+ QFrame( parent )
+{
+ initPlot( title );
+}
+
+//! Destructor
+QwtPlot::~QwtPlot()
+{
+ detachItems( QwtPlotItem::Rtti_PlotItem, autoDelete() );
+
+ delete d_data->layout;
+ deleteAxesData();
+ delete d_data;
+}
+
+/*!
+ \brief Initializes a QwtPlot instance
+ \param title Title text
+ */
+void QwtPlot::initPlot( const QwtText &title )
+{
+ d_data = new PrivateData;
+
+ d_data->layout = new QwtPlotLayout;
+ d_data->autoReplot = false;
+
+ // title
+ d_data->titleLabel = new QwtTextLabel( this );
+ d_data->titleLabel->setObjectName( "QwtPlotTitle" );
+ d_data->titleLabel->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) );
+
+ QwtText text( title );
+ text.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap );
+ d_data->titleLabel->setText( text );
+
+ // legend
+ d_data->legend = NULL;
+
+ // axis
+ initAxesData();
+
+ // canvas
+ d_data->canvas = new QwtPlotCanvas( this );
+ d_data->canvas->setObjectName( "QwtPlotCanvas" );
+ d_data->canvas->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ d_data->canvas->setLineWidth( 2 );
+
+ updateTabOrder();
+
+ setSizePolicy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::MinimumExpanding );
+
+ resize( 200, 200 );
+}
+
+/*!
+ \brief Adds handling of layout requests
+ \param event Event
+*/
+bool QwtPlot::event( QEvent *event )
+{
+ bool ok = QFrame::event( event );
+ switch ( event->type() )
+ {
+ case QEvent::LayoutRequest:
+ updateLayout();
+ break;
+ case QEvent::PolishRequest:
+ replot();
+ break;
+ default:;
+ }
+ return ok;
+}
+
+//! Replots the plot if autoReplot() is \c true.
+void QwtPlot::autoRefresh()
+{
+ if ( d_data->autoReplot )
+ replot();
+}
+
+/*!
+ \brief Set or reset the autoReplot option
+
+ If the autoReplot option is set, the plot will be
+ updated implicitly by manipulating member functions.
+ Since this may be time-consuming, it is recommended
+ to leave this option switched off and call replot()
+ explicitly if necessary.
+
+ The autoReplot option is set to false by default, which
+ means that the user has to call replot() in order to make
+ changes visible.
+ \param tf \c true or \c false. Defaults to \c true.
+ \sa replot()
+*/
+void QwtPlot::setAutoReplot( bool tf )
+{
+ d_data->autoReplot = tf;
+}
+
+/*!
+ \return true if the autoReplot option is set.
+ \sa setAutoReplot()
+*/
+bool QwtPlot::autoReplot() const
+{
+ return d_data->autoReplot;
+}
+
+/*!
+ Change the plot's title
+ \param title New title
+*/
+void QwtPlot::setTitle( const QString &title )
+{
+ if ( title != d_data->titleLabel->text().text() )
+ {
+ d_data->titleLabel->setText( title );
+ updateLayout();
+ }
+}
+
+/*!
+ Change the plot's title
+ \param title New title
+*/
+void QwtPlot::setTitle( const QwtText &title )
+{
+ if ( title != d_data->titleLabel->text() )
+ {
+ d_data->titleLabel->setText( title );
+ updateLayout();
+ }
+}
+
+//! \return Title of the plot
+QwtText QwtPlot::title() const
+{
+ return d_data->titleLabel->text();
+}
+
+//! \return the plot's title
+QwtPlotLayout *QwtPlot::plotLayout()
+{
+ return d_data->layout;
+}
+
+//! \return the plot's layout
+const QwtPlotLayout *QwtPlot::plotLayout() const
+{
+ return d_data->layout;
+}
+
+//! \return the plot's titel label.
+QwtTextLabel *QwtPlot::titleLabel()
+{
+ return d_data->titleLabel;
+}
+
+/*!
+ \return the plot's titel label.
+*/
+const QwtTextLabel *QwtPlot::titleLabel() const
+{
+ return d_data->titleLabel;
+}
+
+/*!
+ \return the plot's legend
+ \sa insertLegend()
+*/
+QwtLegend *QwtPlot::legend()
+{
+ return d_data->legend;
+}
+
+/*!
+ \return the plot's legend
+ \sa insertLegend()
+*/
+const QwtLegend *QwtPlot::legend() const
+{
+ return d_data->legend;
+}
+
+
+/*!
+ \return the plot's canvas
+*/
+QwtPlotCanvas *QwtPlot::canvas()
+{
+ return d_data->canvas;
+}
+
+/*!
+ \return the plot's canvas
+*/
+const QwtPlotCanvas *QwtPlot::canvas() const
+{
+ return d_data->canvas;
+}
+
+/*!
+ Return sizeHint
+ \sa minimumSizeHint()
+*/
+
+QSize QwtPlot::sizeHint() const
+{
+ int dw = 0;
+ int dh = 0;
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ {
+ if ( axisEnabled( axisId ) )
+ {
+ const int niceDist = 40;
+ const QwtScaleWidget *scaleWidget = axisWidget( axisId );
+ const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
+ const int majCnt = scaleDiv.ticks( QwtScaleDiv::MajorTick ).count();
+
+ if ( axisId == yLeft || axisId == yRight )
+ {
+ int hDiff = ( majCnt - 1 ) * niceDist
+ - scaleWidget->minimumSizeHint().height();
+ if ( hDiff > dh )
+ dh = hDiff;
+ }
+ else
+ {
+ int wDiff = ( majCnt - 1 ) * niceDist
+ - scaleWidget->minimumSizeHint().width();
+ if ( wDiff > dw )
+ dw = wDiff;
+ }
+ }
+ }
+ return minimumSizeHint() + QSize( dw, dh );
+}
+
+/*!
+ \brief Return a minimum size hint
+*/
+QSize QwtPlot::minimumSizeHint() const
+{
+ QSize hint = d_data->layout->minimumSizeHint( this );
+ hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
+
+ return hint;
+}
+
+/*!
+ Resize and update internal layout
+ \param e Resize event
+*/
+void QwtPlot::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+ updateLayout();
+}
+
+/*!
+ \brief Redraw the plot
+
+ If the autoReplot option is not set (which is the default)
+ or if any curves are attached to raw data, the plot has to
+ be refreshed explicitly in order to make changes visible.
+
+ \sa setAutoReplot()
+ \warning Calls canvas()->repaint, take care of infinite recursions
+*/
+void QwtPlot::replot()
+{
+ bool doAutoReplot = autoReplot();
+ setAutoReplot( false );
+
+ updateAxes();
+
+ /*
+ Maybe the layout needs to be updated, because of changed
+ axes labels. We need to process them here before painting
+ to avoid that scales and canvas get out of sync.
+ */
+ QApplication::sendPostedEvents( this, QEvent::LayoutRequest );
+
+ d_data->canvas->replot();
+
+ setAutoReplot( doAutoReplot );
+}
+
+/*!
+ \brief Adjust plot content to its current size.
+ \sa resizeEvent()
+*/
+void QwtPlot::updateLayout()
+{
+ d_data->layout->activate( this, contentsRect() );
+
+ QRect titleRect = d_data->layout->titleRect().toRect();
+ QRect scaleRect[QwtPlot::axisCnt];
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ scaleRect[axisId] = d_data->layout->scaleRect( axisId ).toRect();
+ QRect legendRect = d_data->layout->legendRect().toRect();
+ QRect canvasRect = d_data->layout->canvasRect().toRect();
+
+ // resize and show the visible widgets
+ if ( !d_data->titleLabel->text().isEmpty() )
+ {
+ d_data->titleLabel->setGeometry( titleRect );
+ if ( !d_data->titleLabel->isVisibleTo( this ) )
+ d_data->titleLabel->show();
+ }
+ else
+ d_data->titleLabel->hide();
+
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ {
+ if ( axisEnabled( axisId ) )
+ {
+ axisWidget( axisId )->setGeometry( scaleRect[axisId] );
+
+#if 1
+ if ( axisId == xBottom || axisId == xTop )
+ {
+ // do we need this code any longer ???
+
+ QRegion r( scaleRect[axisId] );
+ if ( axisEnabled( yLeft ) )
+ r = r.subtract( QRegion( scaleRect[yLeft] ) );
+ if ( axisEnabled( yRight ) )
+ r = r.subtract( QRegion( scaleRect[yRight] ) );
+ r.translate( -scaleRect[ axisId ].x(),
+ -scaleRect[axisId].y() );
+
+ axisWidget( axisId )->setMask( r );
+ }
+#endif
+ if ( !axisWidget( axisId )->isVisibleTo( this ) )
+ axisWidget( axisId )->show();
+ }
+ else
+ axisWidget( axisId )->hide();
+ }
+
+ if ( d_data->legend &&
+ d_data->layout->legendPosition() != ExternalLegend )
+ {
+ if ( d_data->legend->itemCount() > 0 )
+ {
+ d_data->legend->setGeometry( legendRect );
+ d_data->legend->show();
+ }
+ else
+ d_data->legend->hide();
+ }
+
+ d_data->canvas->setGeometry( canvasRect );
+}
+
+/*!
+ Update the focus tab order
+
+ The order is changed so that the canvas will be in front of the
+ first legend item, or behind the last legend item - depending
+ on the position of the legend.
+*/
+
+void QwtPlot::updateTabOrder()
+{
+ if ( d_data->canvas->focusPolicy() == Qt::NoFocus )
+ return;
+ if ( d_data->legend.isNull()
+ || d_data->layout->legendPosition() == ExternalLegend
+ || d_data->legend->legendItems().count() == 0 )
+ {
+ return;
+ }
+
+ // Depending on the position of the legend the
+ // tab order will be changed that the canvas is
+ // next to the last legend item, or before
+ // the first one.
+
+ const bool canvasFirst =
+ d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
+ d_data->layout->legendPosition() == QwtPlot::RightLegend;
+
+ QWidget *previous = NULL;
+
+ QWidget *w = d_data->canvas;
+ while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
+ {
+ bool isLegendItem = false;
+ if ( w->focusPolicy() != Qt::NoFocus
+ && w->parent() && w->parent() == d_data->legend->contentsWidget() )
+ {
+ isLegendItem = true;
+ }
+
+ if ( canvasFirst )
+ {
+ if ( isLegendItem )
+ break;
+
+ previous = w;
+ }
+ else
+ {
+ if ( isLegendItem )
+ previous = w;
+ else
+ {
+ if ( previous )
+ break;
+ }
+ }
+ }
+
+ if ( previous && previous != d_data->canvas )
+ setTabOrder( previous, d_data->canvas );
+}
+
+/*!
+ Redraw the canvas.
+ \param painter Painter used for drawing
+
+ \warning drawCanvas calls drawItems what is also used
+ for printing. Applications that like to add individual
+ plot items better overload drawItems()
+ \sa drawItems()
+*/
+void QwtPlot::drawCanvas( QPainter *painter )
+{
+ QwtScaleMap maps[axisCnt];
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ maps[axisId] = canvasMap( axisId );
+
+ drawItems( painter, d_data->canvas->contentsRect(), maps );
+}
+
+/*!
+ Redraw the canvas items.
+ \param painter Painter used for drawing
+ \param canvasRect Bounding rectangle where to paint
+ \param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
+*/
+
+void QwtPlot::drawItems( QPainter *painter, const QRectF &canvasRect,
+ const QwtScaleMap map[axisCnt] ) const
+{
+ const QwtPlotItemList& itmList = itemList();
+ for ( QwtPlotItemIterator it = itmList.begin();
+ it != itmList.end(); ++it )
+ {
+ QwtPlotItem *item = *it;
+ if ( item && item->isVisible() )
+ {
+ painter->save();
+
+ painter->setRenderHint( QPainter::Antialiasing,
+ item->testRenderHint( QwtPlotItem::RenderAntialiased ) );
+
+ item->draw( painter,
+ map[item->xAxis()], map[item->yAxis()],
+ canvasRect );
+
+ painter->restore();
+ }
+ }
+}
+
+/*!
+ \param axisId Axis
+ \return Map for the axis on the canvas. With this map pixel coordinates can
+ translated to plot coordinates and vice versa.
+ \sa QwtScaleMap, transform(), invTransform()
+
+*/
+QwtScaleMap QwtPlot::canvasMap( int axisId ) const
+{
+ QwtScaleMap map;
+ if ( !d_data->canvas )
+ return map;
+
+ map.setTransformation( axisScaleEngine( axisId )->transformation() );
+
+ const QwtScaleDiv *sd = axisScaleDiv( axisId );
+ map.setScaleInterval( sd->lowerBound(), sd->upperBound() );
+
+ if ( axisEnabled( axisId ) )
+ {
+ const QwtScaleWidget *s = axisWidget( axisId );
+ if ( axisId == yLeft || axisId == yRight )
+ {
+ double y = s->y() + s->startBorderDist() - d_data->canvas->y();
+ double h = s->height() - s->startBorderDist() - s->endBorderDist();
+ map.setPaintInterval( y + h, y );
+ }
+ else
+ {
+ double x = s->x() + s->startBorderDist() - d_data->canvas->x();
+ double w = s->width() - s->startBorderDist() - s->endBorderDist();
+ map.setPaintInterval( x, x + w );
+ }
+ }
+ else
+ {
+ int margin = 0;
+ if ( !plotLayout()->alignCanvasToScales() )
+ margin = plotLayout()->canvasMargin( axisId );
+
+ const QRect &canvasRect = d_data->canvas->contentsRect();
+ if ( axisId == yLeft || axisId == yRight )
+ {
+ map.setPaintInterval( canvasRect.bottom() - margin,
+ canvasRect.top() + margin );
+ }
+ else
+ {
+ map.setPaintInterval( canvasRect.left() + margin,
+ canvasRect.right() - margin );
+ }
+ }
+ return map;
+}
+
+/*!
+ \brief Change the background of the plotting area
+
+ Sets brush to QPalette::Window of all colorgroups of
+ the palette of the canvas. Using canvas()->setPalette()
+ is a more powerful way to set these colors.
+
+ \param brush New background brush
+ \sa canvasBackground()
+*/
+void QwtPlot::setCanvasBackground( const QBrush &brush )
+{
+ QPalette pal = d_data->canvas->palette();
+ pal.setBrush( QPalette::Window, brush );
+
+ canvas()->setPalette( pal );
+}
+
+/*!
+ Nothing else than: canvas()->palette().brush(
+ QPalette::Normal, QPalette::Window);
+
+ \return Background brush of the plotting area.
+ \sa setCanvasBackground()
+*/
+QBrush QwtPlot::canvasBackground() const
+{
+ return canvas()->palette().brush(
+ QPalette::Normal, QPalette::Window );
+}
+
+/*!
+ \brief Change the border width of the plotting area
+
+ Nothing else than canvas()->setLineWidth(w),
+ left for compatibility only.
+
+ \param width New border width
+*/
+void QwtPlot::setCanvasLineWidth( int width )
+{
+ canvas()->setLineWidth( width );
+ updateLayout();
+}
+
+/*!
+ Nothing else than: canvas()->lineWidth(),
+ left for compatibility only.
+
+ \return the border width of the plotting area
+*/
+int QwtPlot::canvasLineWidth() const
+{
+ return canvas()->lineWidth();
+}
+
+/*!
+ \return \c true if the specified axis exists, otherwise \c false
+ \param axisId axis index
+ */
+bool QwtPlot::axisValid( int axisId )
+{
+ return ( ( axisId >= QwtPlot::yLeft ) && ( axisId < QwtPlot::axisCnt ) );
+}
+
+/*!
+ Called internally when the legend has been clicked on.
+ Emits a legendClicked() signal.
+*/
+void QwtPlot::legendItemClicked()
+{
+ if ( d_data->legend && sender()->isWidgetType() )
+ {
+ QwtPlotItem *plotItem =
+ ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() );
+ if ( plotItem )
+ Q_EMIT legendClicked( plotItem );
+ }
+}
+
+/*!
+ Called internally when the legend has been checked
+ Emits a legendClicked() signal.
+*/
+void QwtPlot::legendItemChecked( bool on )
+{
+ if ( d_data->legend && sender()->isWidgetType() )
+ {
+ QwtPlotItem *plotItem =
+ ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() );
+ if ( plotItem )
+ Q_EMIT legendChecked( plotItem, on );
+ }
+}
+
+/*!
+ \brief Insert a legend
+
+ If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend
+ the legend will be organized in one column from top to down.
+ Otherwise the legend items will be placed in a table
+ with a best fit number of columns from left to right.
+
+ If pos != QwtPlot::ExternalLegend the plot widget will become
+ parent of the legend. It will be deleted when the plot is deleted,
+ or another legend is set with insertLegend().
+
+ \param legend Legend
+ \param pos The legend's position. For top/left position the number
+ of colums will be limited to 1, otherwise it will be set to
+ unlimited.
+
+ \param ratio Ratio between legend and the bounding rect
+ of title, canvas and axes. The legend will be shrinked
+ if it would need more space than the given ratio.
+ The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
+ it will be reset to the default ratio.
+ The default vertical/horizontal ratio is 0.33/0.5.
+
+ \sa legend(), QwtPlotLayout::legendPosition(),
+ QwtPlotLayout::setLegendPosition()
+*/
+void QwtPlot::insertLegend( QwtLegend *legend,
+ QwtPlot::LegendPosition pos, double ratio )
+{
+ d_data->layout->setLegendPosition( pos, ratio );
+
+ if ( legend != d_data->legend )
+ {
+ if ( d_data->legend && d_data->legend->parent() == this )
+ delete d_data->legend;
+
+ d_data->legend = legend;
+
+ if ( d_data->legend )
+ {
+ if ( pos != ExternalLegend )
+ {
+ if ( d_data->legend->parent() != this )
+ d_data->legend->setParent( this );
+ }
+
+ const QwtPlotItemList& itmList = itemList();
+ for ( QwtPlotItemIterator it = itmList.begin();
+ it != itmList.end(); ++it )
+ {
+ ( *it )->updateLegend( d_data->legend );
+ }
+
+ QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
+ d_data->legend->contentsWidget()->layout() );
+ if ( tl )
+ {
+ switch ( d_data->layout->legendPosition() )
+ {
+ case LeftLegend:
+ case RightLegend:
+ tl->setMaxCols( 1 ); // 1 column: align vertical
+ break;
+ case TopLegend:
+ case BottomLegend:
+ tl->setMaxCols( 0 ); // unlimited
+ break;
+ case ExternalLegend:
+ break;
+ }
+ }
+ }
+ updateTabOrder();
+ }
+
+ updateLayout();
+}
diff --git a/src/libpcp_qwt/src/qwt_plot.h b/src/libpcp_qwt/src/qwt_plot.h
new file mode 100644
index 0000000..8a81f9b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot.h
@@ -0,0 +1,290 @@
+/* -*- 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_PLOT_H
+#define QWT_PLOT_H
+
+#include "qwt_global.h"
+#include "qwt_text.h"
+#include "qwt_plot_dict.h"
+#include "qwt_scale_map.h"
+#include "qwt_interval.h"
+#include <qframe.h>
+
+class QwtPlotLayout;
+class QwtLegend;
+class QwtScaleWidget;
+class QwtScaleEngine;
+class QwtScaleDiv;
+class QwtScaleDraw;
+class QwtTextLabel;
+class QwtPlotCanvas;
+
+/*!
+ \brief A 2-D plotting widget
+
+ QwtPlot is a widget for plotting two-dimensional graphs.
+ An unlimited number of plot items can be displayed on
+ its canvas. Plot items might be curves (QwtPlotCurve), markers
+ (QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived
+ from QwtPlotItem.
+ A plot can have up to four axes, with each plot item attached to an x- and
+ a y axis. The scales at the axes can be explicitely set (QwtScaleDiv), or
+ are calculated from the plot items, using algorithms (QwtScaleEngine) which
+ can be configured separately for each axis.
+
+ \image html plot.png
+
+ \par Example
+ The following example shows (schematically) the most simple
+ way to use QwtPlot. By default, only the left and bottom axes are
+ visible and their scales are computed automatically.
+ \verbatim
+#include <qwt_plot.h>
+#include <qwt_plot_curve.h>
+
+QwtPlot *myPlot = new QwtPlot("Two Curves", parent);
+
+// add curves
+QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1");
+QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2");
+
+// connect or copy the data to the curves
+curve1->setData(...);
+curve2->setData(...);
+
+curve1->attach(myPlot);
+curve2->attach(myPlot);
+
+// finally, refresh the plot
+myPlot->replot();
+\endverbatim
+*/
+
+class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict
+{
+ Q_OBJECT
+ Q_PROPERTY( QString propertiesDocument
+ READ grabProperties WRITE applyProperties )
+
+public:
+ //! \brief Axis index
+ enum Axis
+ {
+ //! Y axis left of the canvas
+ yLeft,
+
+ //! Y axis right of the canvas
+ yRight,
+
+ //! X axis below the canvas
+ xBottom,
+
+ //! X axis above the canvas
+ xTop,
+
+ //! Number of axes
+ axisCnt
+ };
+
+ /*!
+ Position of the legend, relative to the canvas.
+
+ \sa insertLegend()
+ \note In case of ExternalLegend, the legend is not
+ handled by QwtPlotRenderer
+ */
+ enum LegendPosition
+ {
+ //! The legend will be left from the QwtPlot::yLeft axis.
+ LeftLegend,
+
+ //! The legend will be right from the QwtPlot::yRight axis.
+ RightLegend,
+
+ //! The legend will be below QwtPlot::xBottom axis.
+ BottomLegend,
+
+ //! The legend will be between QwtPlot::xTop axis and the title.
+ TopLegend,
+
+ /*!
+ External means that only the content of the legend
+ will be handled by QwtPlot, but not its geometry.
+ This type can be used to have a legend in an
+ external window ( or on the canvas ).
+ */
+ ExternalLegend
+ };
+
+ explicit QwtPlot( QWidget * = NULL );
+ explicit QwtPlot( const QwtText &title, QWidget *p = NULL );
+
+ virtual ~QwtPlot();
+
+ void applyProperties( const QString & );
+ QString grabProperties() const;
+
+ void setAutoReplot( bool tf = true );
+ bool autoReplot() const;
+
+ // Layout
+
+ QwtPlotLayout *plotLayout();
+ const QwtPlotLayout *plotLayout() const;
+
+ // Title
+
+ void setTitle( const QString & );
+ void setTitle( const QwtText &t );
+ QwtText title() const;
+
+ QwtTextLabel *titleLabel();
+ const QwtTextLabel *titleLabel() const;
+
+ // Canvas
+
+ QwtPlotCanvas *canvas();
+ const QwtPlotCanvas *canvas() const;
+
+ void setCanvasBackground( const QBrush & );
+ QBrush canvasBackground() const;
+
+ void setCanvasLineWidth( int w );
+ int canvasLineWidth() const;
+
+ virtual QwtScaleMap canvasMap( int axisId ) const;
+
+ double invTransform( int axisId, int pos ) const;
+ double transform( int axisId, double value ) const;
+
+ // Axes
+
+ QwtScaleEngine *axisScaleEngine( int axisId );
+ const QwtScaleEngine *axisScaleEngine( int axisId ) const;
+ void setAxisScaleEngine( int axisId, QwtScaleEngine * );
+
+ void setAxisAutoScale( int axisId, bool on = true );
+ bool axisAutoScale( int axisId ) const;
+
+ void enableAxis( int axisId, bool tf = true );
+ bool axisEnabled( int axisId ) const;
+
+ void setAxisFont( int axisId, const QFont &f );
+ QFont axisFont( int axisId ) const;
+
+ void setAxisScale( int axisId, double min, double max, double step = 0 );
+ void setAxisScaleDiv( int axisId, const QwtScaleDiv & );
+ void setAxisScaleDraw( int axisId, QwtScaleDraw * );
+
+ double axisStepSize( int axisId ) const;
+ QwtInterval axisInterval( int axisId ) const;
+
+ const QwtScaleDiv *axisScaleDiv( int axisId ) const;
+ QwtScaleDiv *axisScaleDiv( int axisId );
+
+ const QwtScaleDraw *axisScaleDraw( int axisId ) const;
+ QwtScaleDraw *axisScaleDraw( int axisId );
+
+ const QwtScaleWidget *axisWidget( int axisId ) const;
+ QwtScaleWidget *axisWidget( int axisId );
+
+ void setAxisLabelAlignment( int axisId, Qt::Alignment );
+ void setAxisLabelRotation( int axisId, double rotation );
+
+ void setAxisTitle( int axisId, const QString & );
+ void setAxisTitle( int axisId, const QwtText & );
+ QwtText axisTitle( int axisId ) const;
+
+ void setAxisMaxMinor( int axisId, int maxMinor );
+ int axisMaxMinor( int axisId ) const;
+
+ void setAxisMaxMajor( int axisId, int maxMajor );
+ int axisMaxMajor( int axisId ) const;
+
+ // Legend
+
+ void insertLegend( QwtLegend *, LegendPosition = QwtPlot::RightLegend,
+ double ratio = -1.0 );
+
+ QwtLegend *legend();
+ const QwtLegend *legend() const;
+
+ // Misc
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ virtual void updateLayout();
+ virtual void drawCanvas( QPainter * );
+
+ void updateAxes();
+
+ virtual bool event( QEvent * );
+
+ virtual void drawItems( QPainter *, const QRectF &,
+ const QwtScaleMap maps[axisCnt] ) const;
+
+Q_SIGNALS:
+ /*!
+ A signal which is emitted when the user has clicked on
+ a legend item, which is in QwtLegend::ClickableItem mode.
+
+ \param plotItem Corresponding plot item of the
+ selected legend item
+
+ \note clicks are disabled as default
+ \sa QwtLegend::setItemMode(), QwtLegend::itemMode()
+ */
+ void legendClicked( QwtPlotItem *plotItem );
+
+ /*!
+ A signal which is emitted when the user has clicked on
+ a legend item, which is in QwtLegend::CheckableItem mode
+
+ \param plotItem Corresponding plot item of the
+ selected legend item
+ \param on True when the legen item is checked
+
+ \note clicks are disabled as default
+ \sa QwtLegend::setItemMode(), QwtLegend::itemMode()
+ */
+
+ void legendChecked( QwtPlotItem *plotItem, bool on );
+
+public Q_SLOTS:
+ virtual void replot();
+ void autoRefresh();
+
+protected Q_SLOTS:
+ virtual void legendItemClicked();
+ virtual void legendItemChecked( bool );
+
+protected:
+ static bool axisValid( int axisId );
+
+ virtual void updateTabOrder();
+
+ virtual void resizeEvent( QResizeEvent *e );
+
+private:
+ void initAxesData();
+ void deleteAxesData();
+ void updateScaleDiv();
+
+ void initPlot( const QwtText &title );
+
+ class AxisData;
+ AxisData *d_axisData[axisCnt];
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_axis.cpp b/src/libpcp_qwt/src/qwt_plot_axis.cpp
new file mode 100644
index 0000000..66f2fa1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_axis.cpp
@@ -0,0 +1,670 @@
+/* -*- 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_plot.h"
+#include "qwt_math.h"
+#include "qwt_scale_widget.h"
+#include "qwt_scale_div.h"
+#include "qwt_scale_engine.h"
+
+class QwtPlot::AxisData
+{
+public:
+ bool isEnabled;
+ bool doAutoScale;
+
+ double minValue;
+ double maxValue;
+ double stepSize;
+
+ int maxMajor;
+ int maxMinor;
+
+ QwtScaleDiv scaleDiv;
+ QwtScaleEngine *scaleEngine;
+ QwtScaleWidget *scaleWidget;
+};
+
+//! Initialize axes
+void QwtPlot::initAxesData()
+{
+ int axisId;
+
+ for ( axisId = 0; axisId < axisCnt; axisId++ )
+ d_axisData[axisId] = new AxisData;
+
+ d_axisData[yLeft]->scaleWidget =
+ new QwtScaleWidget( QwtScaleDraw::LeftScale, this );
+ d_axisData[yRight]->scaleWidget =
+ new QwtScaleWidget( QwtScaleDraw::RightScale, this );
+ d_axisData[xTop]->scaleWidget =
+ new QwtScaleWidget( QwtScaleDraw::TopScale, this );
+ d_axisData[xBottom]->scaleWidget =
+ new QwtScaleWidget( QwtScaleDraw::BottomScale, this );
+
+ d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" );
+ d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" );
+ d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" );
+ d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" );
+
+ QFont fscl( fontInfo().family(), 10 );
+ QFont fttl( fontInfo().family(), 12, QFont::Bold );
+
+ for ( axisId = 0; axisId < axisCnt; axisId++ )
+ {
+ AxisData &d = *d_axisData[axisId];
+
+ d.scaleWidget->setFont( fscl );
+ d.scaleWidget->setMargin( 2 );
+
+ QwtText text = d.scaleWidget->title();
+ text.setFont( fttl );
+ d.scaleWidget->setTitle( text );
+
+ d.doAutoScale = true;
+
+ d.minValue = 0.0;
+ d.maxValue = 1000.0;
+ d.stepSize = 0.0;
+
+ d.maxMinor = 5;
+ d.maxMajor = 8;
+
+ d.scaleEngine = new QwtLinearScaleEngine;
+
+ d.scaleDiv.invalidate();
+ }
+
+ d_axisData[yLeft]->isEnabled = true;
+ d_axisData[yRight]->isEnabled = false;
+ d_axisData[xBottom]->isEnabled = true;
+ d_axisData[xTop]->isEnabled = false;
+}
+
+void QwtPlot::deleteAxesData()
+{
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ {
+ delete d_axisData[axisId]->scaleEngine;
+ delete d_axisData[axisId];
+ d_axisData[axisId] = NULL;
+ }
+}
+
+/*!
+ \return specified axis, or NULL if axisId is invalid.
+ \param axisId axis index
+*/
+const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->scaleWidget;
+
+ return NULL;
+}
+
+/*!
+ \return specified axis, or NULL if axisId is invalid.
+ \param axisId axis index
+*/
+QwtScaleWidget *QwtPlot::axisWidget( int axisId )
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->scaleWidget;
+
+ return NULL;
+}
+
+/*!
+ Change the scale engine for an axis
+
+ \param axisId axis index
+ \param scaleEngine Scale engine
+
+ \sa axisScaleEngine()
+*/
+void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine )
+{
+ if ( axisValid( axisId ) && scaleEngine != NULL )
+ {
+ AxisData &d = *d_axisData[axisId];
+
+ delete d.scaleEngine;
+ d.scaleEngine = scaleEngine;
+
+ d.scaleDiv.invalidate();
+
+ autoRefresh();
+ }
+}
+
+/*!
+ \param axisId axis index
+ \return Scale engine for a specific axis
+*/
+QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId )
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->scaleEngine;
+ else
+ return NULL;
+}
+
+/*!
+ \param axisId axis index
+ \return Scale engine for a specific axis
+*/
+const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->scaleEngine;
+ else
+ return NULL;
+}
+/*!
+ \return \c true if autoscaling is enabled
+ \param axisId axis index
+*/
+bool QwtPlot::axisAutoScale( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->doAutoScale;
+ else
+ return false;
+
+}
+
+/*!
+ \return \c true if a specified axis is enabled
+ \param axisId axis index
+*/
+bool QwtPlot::axisEnabled( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->isEnabled;
+ else
+ return false;
+}
+
+/*!
+ \return the font of the scale labels for a specified axis
+ \param axisId axis index
+*/
+QFont QwtPlot::axisFont( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return axisWidget( axisId )->font();
+ else
+ return QFont();
+
+}
+
+/*!
+ \return the maximum number of major ticks for a specified axis
+ \param axisId axis index
+ \sa setAxisMaxMajor()
+*/
+int QwtPlot::axisMaxMajor( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->maxMajor;
+ else
+ return 0;
+}
+
+/*!
+ \return the maximum number of minor ticks for a specified axis
+ \param axisId axis index
+ \sa setAxisMaxMinor()
+*/
+int QwtPlot::axisMaxMinor( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return d_axisData[axisId]->maxMinor;
+ else
+ return 0;
+}
+
+/*!
+ \brief Return the scale division of a specified axis
+
+ axisScaleDiv(axisId)->lowerBound(), axisScaleDiv(axisId)->upperBound()
+ are the current limits of the axis scale.
+
+ \param axisId axis index
+ \return Scale division
+
+ \sa QwtScaleDiv, setAxisScaleDiv()
+*/
+const QwtScaleDiv *QwtPlot::axisScaleDiv( int axisId ) const
+{
+ if ( !axisValid( axisId ) )
+ return NULL;
+
+ return &d_axisData[axisId]->scaleDiv;
+}
+
+/*!
+ \brief Return the scale division of a specified axis
+
+ axisScaleDiv(axisId)->lowerBound(), axisScaleDiv(axisId)->upperBound()
+ are the current limits of the axis scale.
+
+ \param axisId axis index
+ \return Scale division
+
+ \sa QwtScaleDiv, setAxisScaleDiv()
+*/
+QwtScaleDiv *QwtPlot::axisScaleDiv( int axisId )
+{
+ if ( !axisValid( axisId ) )
+ return NULL;
+
+ return &d_axisData[axisId]->scaleDiv;
+}
+
+/*!
+ \returns the scale draw of a specified axis
+ \param axisId axis index
+ \return specified scaleDraw for axis, or NULL if axis is invalid.
+ \sa QwtScaleDraw
+*/
+const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const
+{
+ if ( !axisValid( axisId ) )
+ return NULL;
+
+ return axisWidget( axisId )->scaleDraw();
+}
+
+/*!
+ \returns the scale draw of a specified axis
+ \param axisId axis index
+ \return specified scaleDraw for axis, or NULL if axis is invalid.
+ \sa QwtScaleDraw
+*/
+QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId )
+{
+ if ( !axisValid( axisId ) )
+ return NULL;
+
+ return axisWidget( axisId )->scaleDraw();
+}
+
+/*!
+ Return the step size parameter, that has been set
+ in setAxisScale. This doesn't need to be the step size
+ of the current scale.
+
+ \param axisId axis index
+ \return step size parameter value
+
+ \sa setAxisScale()
+*/
+double QwtPlot::axisStepSize( int axisId ) const
+{
+ if ( !axisValid( axisId ) )
+ return 0;
+
+ return d_axisData[axisId]->stepSize;
+}
+
+/*!
+ \brief Return the current interval of the specified axis
+
+ This is only a convenience function for axisScaleDiv( axisId )->interval();
+
+ \param axisId axis index
+ \return Scale interval
+
+ \sa QwtScaleDiv, axisScaleDiv()
+*/
+QwtInterval QwtPlot::axisInterval( int axisId ) const
+{
+ if ( !axisValid( axisId ) )
+ return QwtInterval();
+
+ return d_axisData[axisId]->scaleDiv.interval();
+}
+
+/*!
+ \return the title of a specified axis
+ \param axisId axis index
+*/
+QwtText QwtPlot::axisTitle( int axisId ) const
+{
+ if ( axisValid( axisId ) )
+ return axisWidget( axisId )->title();
+ else
+ return QwtText();
+}
+
+/*!
+ \brief Enable or disable a specified axis
+
+ When an axis is disabled, this only means that it is not
+ visible on the screen. Curves, markers and can be attached
+ to disabled axes, and transformation of screen coordinates
+ into values works as normal.
+
+ Only xBottom and yLeft are enabled by default.
+ \param axisId axis index
+ \param tf \c true (enabled) or \c false (disabled)
+*/
+void QwtPlot::enableAxis( int axisId, bool tf )
+{
+ if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled )
+ {
+ d_axisData[axisId]->isEnabled = tf;
+ updateLayout();
+ }
+}
+
+/*!
+ Transform the x or y coordinate of a position in the
+ drawing region into a value.
+ \param axisId axis index
+ \param pos position
+ \warning The position can be an x or a y coordinate,
+ depending on the specified axis.
+*/
+double QwtPlot::invTransform( int axisId, int pos ) const
+{
+ if ( axisValid( axisId ) )
+ return( canvasMap( axisId ).invTransform( pos ) );
+ else
+ return 0.0;
+}
+
+
+/*!
+ \brief Transform a value into a coordinate in the plotting region
+ \param axisId axis index
+ \param value value
+ \return X or y coordinate in the plotting region corresponding
+ to the value.
+*/
+double QwtPlot::transform( int axisId, double value ) const
+{
+ if ( axisValid( axisId ) )
+ return( canvasMap( axisId ).transform( value ) );
+ else
+ return 0.0;
+}
+
+/*!
+ \brief Change the font of an axis
+ \param axisId axis index
+ \param f font
+ \warning This function changes the font of the tick labels,
+ not of the axis title.
+*/
+void QwtPlot::setAxisFont( int axisId, const QFont &f )
+{
+ if ( axisValid( axisId ) )
+ axisWidget( axisId )->setFont( f );
+}
+
+/*!
+ \brief Enable autoscaling for a specified axis
+
+ This member function is used to switch back to autoscaling mode
+ after a fixed scale has been set. Autoscaling is enabled by default.
+
+ \param axisId axis index
+ \param on On/Off
+ \sa setAxisScale(), setAxisScaleDiv(), updateAxes()
+
+ \note The autoscaling flag has no effect until updateAxes() is executed
+ ( called by replot() ).
+*/
+void QwtPlot::setAxisAutoScale( int axisId, bool on )
+{
+ if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) )
+ {
+ d_axisData[axisId]->doAutoScale = on;
+ autoRefresh();
+ }
+}
+
+/*!
+ \brief Disable autoscaling and specify a fixed scale for a selected axis.
+ \param axisId axis index
+ \param min
+ \param max minimum and maximum of the scale
+ \param stepSize Major step size. If <code>step == 0</code>, the step size is
+ calculated automatically using the maxMajor setting.
+ \sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize()
+*/
+void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize )
+{
+ if ( axisValid( axisId ) )
+ {
+ AxisData &d = *d_axisData[axisId];
+
+ d.doAutoScale = false;
+ d.scaleDiv.invalidate();
+
+ d.minValue = min;
+ d.maxValue = max;
+ d.stepSize = stepSize;
+
+ autoRefresh();
+ }
+}
+
+/*!
+ \brief Disable autoscaling and specify a fixed scale for a selected axis.
+ \param axisId axis index
+ \param scaleDiv Scale division
+ \sa setAxisScale(), setAxisAutoScale()
+*/
+void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv )
+{
+ if ( axisValid( axisId ) )
+ {
+ AxisData &d = *d_axisData[axisId];
+
+ d.doAutoScale = false;
+ d.scaleDiv = scaleDiv;
+
+ autoRefresh();
+ }
+}
+
+/*!
+ \brief Set a scale draw
+ \param axisId axis index
+ \param scaleDraw object responsible for drawing scales.
+
+ By passing scaleDraw it is possible to extend QwtScaleDraw
+ functionality and let it take place in QwtPlot. Please note
+ that scaleDraw has to be created with new and will be deleted
+ by the corresponding QwtScale member ( like a child object ).
+
+ \sa QwtScaleDraw, QwtScaleWidget
+ \warning The attributes of scaleDraw will be overwritten by those of the
+ previous QwtScaleDraw.
+*/
+
+void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw )
+{
+ if ( axisValid( axisId ) )
+ {
+ axisWidget( axisId )->setScaleDraw( scaleDraw );
+ autoRefresh();
+ }
+}
+
+/*!
+ Change the alignment of the tick labels
+ \param axisId axis index
+ \param alignment Or'd Qt::AlignmentFlags see <qnamespace.h>
+ \sa QwtScaleDraw::setLabelAlignment()
+*/
+void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment )
+{
+ if ( axisValid( axisId ) )
+ axisWidget( axisId )->setLabelAlignment( alignment );
+}
+
+/*!
+ Rotate all tick labels
+ \param axisId axis index
+ \param rotation Angle in degrees. When changing the label rotation,
+ the label alignment might be adjusted too.
+ \sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment()
+*/
+void QwtPlot::setAxisLabelRotation( int axisId, double rotation )
+{
+ if ( axisValid( axisId ) )
+ axisWidget( axisId )->setLabelRotation( rotation );
+}
+
+/*!
+ Set the maximum number of minor scale intervals for a specified axis
+
+ \param axisId axis index
+ \param maxMinor maximum number of minor steps
+ \sa axisMaxMinor()
+*/
+void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor )
+{
+ if ( axisValid( axisId ) )
+ {
+ maxMinor = qBound( 0, maxMinor, 100 );
+
+ AxisData &d = *d_axisData[axisId];
+ if ( maxMinor != d.maxMinor )
+ {
+ d.maxMinor = maxMinor;
+ d.scaleDiv.invalidate();
+ autoRefresh();
+ }
+ }
+}
+
+/*!
+ Set the maximum number of major scale intervals for a specified axis
+
+ \param axisId axis index
+ \param maxMajor maximum number of major steps
+ \sa axisMaxMajor()
+*/
+void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor )
+{
+ if ( axisValid( axisId ) )
+ {
+ maxMajor = qBound( 1, maxMajor, 10000 );
+
+ AxisData &d = *d_axisData[axisId];
+ if ( maxMajor != d.maxMajor )
+ {
+ d.maxMajor = maxMajor;
+ d.scaleDiv.invalidate();
+ autoRefresh();
+ }
+ }
+}
+
+/*!
+ \brief Change the title of a specified axis
+ \param axisId axis index
+ \param title axis title
+*/
+void QwtPlot::setAxisTitle( int axisId, const QString &title )
+{
+ if ( axisValid( axisId ) )
+ axisWidget( axisId )->setTitle( title );
+}
+
+/*!
+ \brief Change the title of a specified axis
+ \param axisId axis index
+ \param title axis title
+*/
+void QwtPlot::setAxisTitle( int axisId, const QwtText &title )
+{
+ if ( axisValid( axisId ) )
+ axisWidget( axisId )->setTitle( title );
+}
+
+//! Rebuild the scales
+void QwtPlot::updateAxes()
+{
+ // Find bounding interval of the item data
+ // for all axes, where autoscaling is enabled
+
+ QwtInterval intv[axisCnt];
+
+ const QwtPlotItemList& itmList = itemList();
+
+ QwtPlotItemIterator it;
+ for ( it = itmList.begin(); it != itmList.end(); ++it )
+ {
+ const QwtPlotItem *item = *it;
+
+ if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) )
+ continue;
+
+ if ( !item->isVisible() )
+ continue;
+
+ if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) )
+ {
+ const QRectF rect = item->boundingRect();
+ intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() );
+ intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() );
+ }
+ }
+
+ // Adjust scales
+
+ for ( int axisId = 0; axisId < axisCnt; axisId++ )
+ {
+ AxisData &d = *d_axisData[axisId];
+
+ double minValue = d.minValue;
+ double maxValue = d.maxValue;
+ double stepSize = d.stepSize;
+
+ if ( d.doAutoScale && intv[axisId].isValid() )
+ {
+ d.scaleDiv.invalidate();
+
+ minValue = intv[axisId].minValue();
+ maxValue = intv[axisId].maxValue();
+
+ d.scaleEngine->autoScale( d.maxMajor,
+ minValue, maxValue, stepSize );
+ }
+ if ( !d.scaleDiv.isValid() )
+ {
+ d.scaleDiv = d.scaleEngine->divideScale(
+ minValue, maxValue,
+ d.maxMajor, d.maxMinor, stepSize );
+ }
+
+ QwtScaleWidget *scaleWidget = axisWidget( axisId );
+ scaleWidget->setScaleDiv(
+ d.scaleEngine->transformation(), d.scaleDiv );
+
+ int startDist, endDist;
+ scaleWidget->getBorderDistHint( startDist, endDist );
+ scaleWidget->setBorderDist( startDist, endDist );
+ }
+
+ for ( it = itmList.begin(); it != itmList.end(); ++it )
+ {
+ QwtPlotItem *item = *it;
+ item->updateScaleDiv( *axisScaleDiv( item->xAxis() ),
+ *axisScaleDiv( item->yAxis() ) );
+ }
+}
+
diff --git a/src/libpcp_qwt/src/qwt_plot_canvas.cpp b/src/libpcp_qwt/src/qwt_plot_canvas.cpp
new file mode 100644
index 0000000..69669d2
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_canvas.cpp
@@ -0,0 +1,1095 @@
+/* -*- 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_plot_canvas.h"
+#include "qwt_painter.h"
+#include "qwt_null_paintdevice.h"
+#include "qwt_math.h"
+#include "qwt_plot.h"
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qpaintengine.h>
+#include <qevent.h>
+#include <qbitmap.h>
+#ifdef Q_WS_X11
+#include <qx11info_x11.h>
+#endif
+
+class QwtStyleSheetRecorder: public QwtNullPaintDevice
+{
+public:
+ QwtStyleSheetRecorder( const QSize &size ):
+ QwtNullPaintDevice( QPaintEngine::AllFeatures )
+ {
+ setSize( size );
+ }
+
+ virtual void updateState( const QPaintEngineState &state )
+ {
+ if ( state.state() & QPaintEngine::DirtyPen )
+ {
+ d_pen = state.pen();
+ }
+ if ( state.state() & QPaintEngine::DirtyBrush )
+ {
+ d_brush = state.brush();
+ }
+ if ( state.state() & QPaintEngine::DirtyBrushOrigin )
+ {
+ d_origin = state.brushOrigin();
+ }
+ }
+
+ virtual void drawRects(const QRectF *rects, int count )
+ {
+ for ( int i = 0; i < count; i++ )
+ border.rectList += rects[i];
+ }
+
+ virtual void drawPath( const QPainterPath &path )
+ {
+ const QRectF rect( QPointF( 0.0, 0.0 ) , size() );
+ if ( path.controlPointRect().contains( rect.center() ) )
+ {
+ setCornerRects( path );
+ alignCornerRects( rect );
+
+ background.path = path;
+ background.brush = d_brush;
+ background.origin = d_origin;
+ }
+ else
+ {
+ border.pathList += path;
+ }
+ }
+
+ void setCornerRects( const QPainterPath &path )
+ {
+ QPointF pos( 0.0, 0.0 );
+
+ for ( int i = 0; i < path.elementCount(); i++ )
+ {
+ QPainterPath::Element el = path.elementAt(i);
+ switch( el.type )
+ {
+ case QPainterPath::MoveToElement:
+ case QPainterPath::LineToElement:
+ {
+ pos.setX( el.x );
+ pos.setY( el.y );
+ break;
+ }
+ case QPainterPath::CurveToElement:
+ {
+ QRectF r( pos, QPointF( el.x, el.y ) );
+ clipRects += r.normalized();
+
+ pos.setX( el.x );
+ pos.setY( el.y );
+
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ {
+ if ( clipRects.size() > 0 )
+ {
+ QRectF r = clipRects.last();
+ r.setCoords(
+ qMin( r.left(), el.x ),
+ qMin( r.top(), el.y ),
+ qMax( r.right(), el.x ),
+ qMax( r.bottom(), el.y )
+ );
+ clipRects.last() = r.normalized();
+ }
+ break;
+ }
+ }
+ }
+ }
+
+private:
+ void alignCornerRects( const QRectF &rect )
+ {
+ for ( int i = 0; i < clipRects.size(); i++ )
+ {
+ QRectF &r = clipRects[i];
+ if ( r.center().x() < rect.center().x() )
+ r.setLeft( rect.left() );
+ else
+ r.setRight( rect.right() );
+
+ if ( r.center().y() < rect.center().y() )
+ r.setTop( rect.top() );
+ else
+ r.setBottom( rect.bottom() );
+ }
+ }
+
+
+public:
+ QVector<QRectF> clipRects;
+
+ struct Border
+ {
+ QList<QPainterPath> pathList;
+ QList<QRectF> rectList;
+ QRegion clipRegion;
+ } border;
+
+ struct Background
+ {
+ QPainterPath path;
+ QBrush brush;
+ QPointF origin;
+ } background;
+
+private:
+ QPen d_pen;
+ QBrush d_brush;
+ QPointF d_origin;
+};
+
+static void qwtDrawBackground( QPainter *painter, QWidget *widget )
+{
+ const QBrush &brush =
+ widget->palette().brush( widget->backgroundRole() );
+
+ if ( brush.style() == Qt::TexturePattern )
+ {
+ QPixmap pm( widget->size() );
+#if QT_VERSION >= 0x050000
+ QwtPainter::fillPixmap( widget, pm );
+#else
+ pm.fill( widget, 0, 0 );
+#endif
+ painter->drawPixmap( 0, 0, pm );
+ }
+ else if ( brush.gradient() )
+ {
+ QVector<QRect> rects;
+
+ if ( brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode )
+ {
+ rects += widget->rect();
+ }
+ else
+ {
+ rects = painter->clipRegion().rects();
+ }
+
+#if 1
+ bool useRaster = false;
+
+ if ( painter->paintEngine()->type() == QPaintEngine::X11 )
+ {
+ // Qt 4.7.1: gradients on X11 are broken ( subrects +
+ // QGradient::StretchToDeviceMode ) and horrible slow.
+ // As workaround we have to use the raster paintengine.
+ // Even if the QImage -> QPixmap translation is slow
+ // it is three times faster, than using X11 directly
+
+ useRaster = true;
+ }
+#endif
+ if ( useRaster )
+ {
+ QImage::Format format = QImage::Format_RGB32;
+
+ const QGradientStops stops = brush.gradient()->stops();
+ for ( int i = 0; i < stops.size(); i++ )
+ {
+ if ( stops[i].second.alpha() != 255 )
+ {
+ // don't use Format_ARGB32_Premultiplied. It's
+ // recommended by the Qt docs, but QPainter::drawImage()
+ // is horrible slow on X11.
+
+ format = QImage::Format_ARGB32;
+ break;
+ }
+ }
+
+ QImage image( widget->size(), format );
+
+ QPainter p( &image );
+ p.setPen( Qt::NoPen );
+ p.setBrush( brush );
+
+ p.drawRects( rects );
+
+ p.end();
+
+ painter->drawImage( 0, 0, image );
+ }
+ else
+ {
+ painter->save();
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( brush );
+
+ painter->drawRects( rects );
+
+ painter->restore();
+ }
+ }
+ else
+ {
+ painter->save();
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( brush );
+
+ painter->drawRects( painter->clipRegion().rects() );
+
+ painter->restore();
+ }
+}
+
+static inline void qwtRevertPath( QPainterPath &path )
+{
+ if ( path.elementCount() == 4 )
+ {
+ QPainterPath::Element el0 = path.elementAt(0);
+ QPainterPath::Element el3 = path.elementAt(3);
+
+ path.setElementPositionAt( 0, el3.x, el3.y );
+ path.setElementPositionAt( 3, el0.x, el0.y );
+ }
+}
+
+static QPainterPath qwtCombinePathList( const QRectF &rect,
+ const QList<QPainterPath> &pathList )
+{
+ if ( pathList.isEmpty() )
+ return QPainterPath();
+
+ QPainterPath ordered[8]; // starting top left
+
+ for ( int i = 0; i < pathList.size(); i++ )
+ {
+ int index = -1;
+ QPainterPath subPath = pathList[i];
+
+ const QRectF br = pathList[i].controlPointRect();
+ if ( br.center().x() < rect.center().x() )
+ {
+ if ( br.center().y() < rect.center().y() )
+ {
+ if ( qAbs( br.top() - rect.top() ) <
+ qAbs( br.left() - rect.left() ) )
+ {
+ index = 1;
+ }
+ else
+ {
+ index = 0;
+ }
+ }
+ else
+ {
+ if ( qAbs( br.bottom() - rect.bottom() ) <
+ qAbs( br.left() - rect.left() ) )
+ {
+ index = 6;
+ }
+ else
+ {
+ index = 7;
+ }
+ }
+
+ if ( subPath.currentPosition().y() > br.center().y() )
+ qwtRevertPath( subPath );
+ }
+ else
+ {
+ if ( br.center().y() < rect.center().y() )
+ {
+ if ( qAbs( br.top() - rect.top() ) <
+ qAbs( br.right() - rect.right() ) )
+ {
+ index = 2;
+ }
+ else
+ {
+ index = 3;
+ }
+ }
+ else
+ {
+ if ( qAbs( br.bottom() - rect.bottom() ) <
+ qAbs( br.right() - rect.right() ) )
+ {
+ index = 5;
+ }
+ else
+ {
+ index = 4;
+ }
+ }
+ if ( subPath.currentPosition().y() < br.center().y() )
+ qwtRevertPath( subPath );
+ }
+ ordered[index] = subPath;
+ }
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() )
+ {
+ // we don't accept incomplete rounded borders
+ return QPainterPath();
+ }
+ }
+
+
+ const QPolygonF corners( rect );
+
+ QPainterPath path;
+ //path.moveTo( rect.topLeft() );
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ if ( ordered[2 * i].isEmpty() )
+ {
+ path.lineTo( corners[i] );
+ }
+ else
+ {
+ path.connectPath( ordered[2 * i] );
+ path.connectPath( ordered[2 * i + 1] );
+ }
+ }
+
+ path.closeSubpath();
+
+#if 0
+ return path.simplified();
+#else
+ return path;
+#endif
+}
+
+static inline void qwtDrawStyledBackground(
+ QWidget *w, QPainter *painter )
+{
+ QStyleOption opt;
+ opt.initFrom(w);
+ w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
+}
+
+static QWidget *qwtBackgroundWidget( QWidget *w )
+{
+ if ( w->parentWidget() == NULL )
+ return w;
+
+ if ( w->autoFillBackground() )
+ {
+ const QBrush brush = w->palette().brush( w->backgroundRole() );
+ if ( brush.color().alpha() > 0 )
+ return w;
+ }
+
+ if ( w->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ QImage image( 1, 1, QImage::Format_ARGB32 );
+ image.fill( Qt::transparent );
+
+ QPainter painter( &image );
+ painter.translate( -w->rect().center() );
+ qwtDrawStyledBackground( w, &painter );
+ painter.end();
+
+ if ( qAlpha( image.pixel( 0, 0 ) ) != 0 )
+ return w;
+ }
+
+ return qwtBackgroundWidget( w->parentWidget() );
+}
+
+static void qwtFillBackground( QPainter *painter,
+ QWidget *widget, const QVector<QRectF> &fillRects )
+{
+ if ( fillRects.isEmpty() )
+ return;
+
+ QRegion clipRegion;
+ if ( painter->hasClipping() )
+ clipRegion = painter->transform().map( painter->clipRegion() );
+ else
+ clipRegion = widget->contentsRect();
+
+ // Try to find out which widget fills
+ // the unfilled areas of the styled background
+
+ QWidget *bgWidget = qwtBackgroundWidget( widget->parentWidget() );
+
+ for ( int i = 0; i < fillRects.size(); i++ )
+ {
+ const QRect rect = fillRects[i].toAlignedRect();
+ if ( clipRegion.intersects( rect ) )
+ {
+ const QPoint topLeft = widget->mapTo( bgWidget, rect.topLeft() );
+
+ QPixmap pm( rect.size() );
+#if QT_VERSION >= 0x050000
+ QwtPainter::fillPixmap( bgWidget, pm, topLeft );
+#else
+ pm.fill( bgWidget, topLeft );
+#endif
+ painter->drawPixmap( rect, pm );
+ }
+ }
+}
+
+static void qwtFillBackground( QPainter *painter, QwtPlotCanvas *canvas )
+{
+ QVector<QRectF> rects;
+
+ if ( canvas->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ QwtStyleSheetRecorder recorder( canvas->size() );
+
+ QPainter p( &recorder );
+ qwtDrawStyledBackground( canvas, &p );
+ p.end();
+
+ if ( recorder.background.brush.isOpaque() )
+ rects = recorder.clipRects;
+ else
+ rects += canvas->rect();
+ }
+ else
+ {
+ const QRectF r = canvas->rect();
+ const double radius = canvas->borderRadius();
+ if ( radius > 0.0 )
+ {
+ QSizeF sz( radius, radius );
+
+ rects += QRectF( r.topLeft(), sz );
+ rects += QRectF( r.topRight() - QPointF( radius, 0 ), sz );
+ rects += QRectF( r.bottomRight() - QPointF( radius, radius ), sz );
+ rects += QRectF( r.bottomLeft() - QPointF( 0, radius ), sz );
+ }
+ }
+
+ qwtFillBackground( painter, canvas, rects);
+}
+
+
+class QwtPlotCanvas::PrivateData
+{
+public:
+ PrivateData():
+ focusIndicator( NoFocusIndicator ),
+ borderRadius( 0 ),
+ paintAttributes( 0 ),
+ backingStore( NULL )
+ {
+ styleSheet.hasBorder = false;
+ }
+
+ ~PrivateData()
+ {
+ delete backingStore;
+ }
+
+ FocusIndicator focusIndicator;
+ double borderRadius;
+ QwtPlotCanvas::PaintAttributes paintAttributes;
+ QPixmap *backingStore;
+
+ struct StyleSheet
+ {
+ bool hasBorder;
+ QPainterPath borderPath;
+ QVector<QRectF> cornerRects;
+
+ struct StyleSheetBackground
+ {
+ QBrush brush;
+ QPointF origin;
+ } background;
+
+ } styleSheet;
+
+};
+
+//! Sets a cross cursor, enables QwtPlotCanvas::BackingStore
+
+QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ):
+ QFrame( plot )
+{
+ d_data = new PrivateData;
+
+#ifndef QT_NO_CURSOR
+ setCursor( Qt::CrossCursor );
+#endif
+
+ setAutoFillBackground( true );
+ setPaintAttribute( QwtPlotCanvas::BackingStore, true );
+ setPaintAttribute( QwtPlotCanvas::Opaque, true );
+ setPaintAttribute( QwtPlotCanvas::HackStyledBackground, true );
+}
+
+//! Destructor
+QwtPlotCanvas::~QwtPlotCanvas()
+{
+ delete d_data;
+}
+
+//! Return parent plot widget
+QwtPlot *QwtPlotCanvas::plot()
+{
+ return qobject_cast<QwtPlot *>( parent() );
+}
+
+//! Return parent plot widget
+const QwtPlot *QwtPlotCanvas::plot() const
+{
+ return qobject_cast<const QwtPlot *>( parent() );
+}
+
+/*!
+ \brief Changing the paint attributes
+
+ \param attribute Paint attribute
+ \param on On/Off
+
+ \sa testPaintAttribute(), backingStore()
+*/
+void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on )
+{
+ if ( bool( d_data->paintAttributes & attribute ) == on )
+ return;
+
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+
+ switch ( attribute )
+ {
+ case BackingStore:
+ {
+ if ( on )
+ {
+ if ( d_data->backingStore == NULL )
+ d_data->backingStore = new QPixmap();
+
+ if ( isVisible() )
+ {
+#if QT_VERSION >= 0x050000
+ *d_data->backingStore = grab( rect() );
+#else
+ *d_data->backingStore =
+ QPixmap::grabWidget( this, rect() );
+#endif
+ }
+ }
+ else
+ {
+ delete d_data->backingStore;
+ d_data->backingStore = NULL;
+ }
+ break;
+ }
+ case Opaque:
+ {
+ if ( on )
+ setAttribute( Qt::WA_OpaquePaintEvent, true );
+
+ break;
+ }
+ case HackStyledBackground:
+ case ImmediatePaint:
+ {
+ break;
+ }
+ }
+}
+
+/*!
+ Test wether a paint attribute is enabled
+
+ \param attribute Paint attribute
+ \return true if the attribute is enabled
+ \sa setPaintAttribute()
+*/
+bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const
+{
+ return d_data->paintAttributes & attribute;
+}
+
+//! \return Backing store, might be null
+const QPixmap *QwtPlotCanvas::backingStore() const
+{
+ return d_data->backingStore;
+}
+
+//! Invalidate the internal backing store
+void QwtPlotCanvas::invalidateBackingStore()
+{
+ if ( d_data->backingStore )
+ *d_data->backingStore = QPixmap();
+}
+
+/*!
+ Set the focus indicator
+
+ \sa FocusIndicator, focusIndicator()
+*/
+void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator )
+{
+ d_data->focusIndicator = focusIndicator;
+}
+
+/*!
+ \return Focus indicator
+
+ \sa FocusIndicator, setFocusIndicator()
+*/
+QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const
+{
+ return d_data->focusIndicator;
+}
+
+/*!
+ Set the radius for the corners of the border frame
+
+ \param radius Radius of a rounded corner
+ \sa borderRadius()
+*/
+void QwtPlotCanvas::setBorderRadius( double radius )
+{
+ d_data->borderRadius = qMax( 0.0, radius );
+}
+
+/*!
+ \return Radius for the corners of the border frame
+ \sa setBorderRadius()
+*/
+double QwtPlotCanvas::borderRadius() const
+{
+ return d_data->borderRadius;
+}
+
+/*!
+ Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
+ \param event Qt Event
+*/
+bool QwtPlotCanvas::event( QEvent *event )
+{
+ if ( event->type() == QEvent::PolishRequest )
+ {
+ if ( testPaintAttribute( QwtPlotCanvas::Opaque ) )
+ {
+ // Setting a style sheet changes the
+ // Qt::WA_OpaquePaintEvent attribute, but we insist
+ // on painting the background.
+
+ setAttribute( Qt::WA_OpaquePaintEvent, true );
+ }
+ }
+
+ if ( event->type() == QEvent::PolishRequest ||
+ event->type() == QEvent::StyleChange )
+ {
+ updateStyleSheetInfo();
+ }
+
+ return QFrame::event( event );
+}
+
+/*!
+ Paint event
+ \param event Paint event
+*/
+void QwtPlotCanvas::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+ painter.setClipRegion( event->region() );
+
+ if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) &&
+ d_data->backingStore != NULL )
+ {
+ QPixmap &bs = *d_data->backingStore;
+ if ( bs.size() != size() )
+ {
+ bs = QPixmap( size() );
+
+#ifdef Q_WS_X11
+ if ( bs.x11Info().screen() != x11Info().screen() )
+ bs.x11SetScreen( x11Info().screen() );
+#endif
+
+ if ( testAttribute(Qt::WA_StyledBackground) )
+ {
+ QPainter p( &bs );
+ qwtFillBackground( &p, this );
+ drawCanvas( &p, true );
+ }
+ else
+ {
+ QPainter p;
+ if ( d_data->borderRadius <= 0.0 )
+ {
+#if QT_VERSION >= 0x050000
+ QwtPainter::fillPixmap( this, bs );
+#else
+ bs.fill( this, 0, 0 );
+#endif
+ p.begin( &bs );
+ drawCanvas( &p, false );
+ }
+ else
+ {
+ p.begin( &bs );
+ qwtFillBackground( &p, this );
+ drawCanvas( &p, true );
+ }
+
+ if ( frameWidth() > 0 )
+ drawBorder( &p );
+ }
+ }
+
+ painter.drawPixmap( 0, 0, *d_data->backingStore );
+ }
+ else
+ {
+ if ( testAttribute(Qt::WA_StyledBackground ) )
+ {
+ if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
+ {
+ qwtFillBackground( &painter, this );
+ drawCanvas( &painter, true );
+ }
+ else
+ {
+ drawCanvas( &painter, false );
+ }
+ }
+ else
+ {
+ if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
+ {
+ if ( autoFillBackground() )
+ qwtDrawBackground( &painter, this );
+ }
+
+ drawCanvas( &painter, false );
+
+ if ( frameWidth() > 0 )
+ drawBorder( &painter );
+ }
+ }
+
+ if ( hasFocus() && focusIndicator() == CanvasFocusIndicator )
+ drawFocusIndicator( &painter );
+}
+
+void QwtPlotCanvas::drawCanvas( QPainter *painter, bool withBackground )
+{
+ bool hackStyledBackground = false;
+
+ if ( withBackground && testAttribute( Qt::WA_StyledBackground )
+ && testPaintAttribute( HackStyledBackground ) )
+ {
+ // Antialiasing rounded borders is done by
+ // inserting pixels with colors between the
+ // border color and the color on the canvas,
+ // When the border is painted before the plot items
+ // these colors are interpolated for the canvas
+ // and the plot items need to be clipped excluding
+ // the anialiased pixels. In situations, where
+ // the plot items fill the area at the rounded
+ // borders this is noticeable.
+ // The only way to avoid these annoying "artefacts"
+ // is to paint the border on top of the plot items.
+
+ if ( d_data->styleSheet.hasBorder &&
+ !d_data->styleSheet.borderPath.isEmpty() )
+ {
+ // We have a border with at least one rounded corner
+ hackStyledBackground = true;
+ }
+ }
+
+ if ( withBackground )
+ {
+ painter->save();
+
+ if ( testAttribute( Qt::WA_StyledBackground ) )
+ {
+ if ( hackStyledBackground )
+ {
+ // paint background without border
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( d_data->styleSheet.background.brush );
+ painter->setBrushOrigin( d_data->styleSheet.background.origin );
+ painter->setClipPath( d_data->styleSheet.borderPath );
+ painter->drawRect( contentsRect() );
+ }
+ else
+ {
+ qwtDrawStyledBackground( this, painter );
+ }
+ }
+ else if ( autoFillBackground() )
+ {
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( palette().brush( backgroundRole() ) );
+
+ if ( d_data->borderRadius > 0.0 )
+ {
+ if ( frameWidth() > 0 )
+ {
+ painter->setClipPath( borderPath( rect() ) );
+ painter->drawRect( rect() );
+ }
+ else
+ {
+ painter->setRenderHint( QPainter::Antialiasing, true );
+ painter->drawPath( borderPath( rect() ) );
+ }
+ }
+ else
+ {
+ painter->drawRect( contentsRect() );
+ }
+ }
+
+ painter->restore();
+ }
+
+ painter->save();
+
+ if ( !d_data->styleSheet.borderPath.isEmpty() )
+ {
+ painter->setClipPath(
+ d_data->styleSheet.borderPath, Qt::IntersectClip );
+ }
+ else
+ {
+ if ( d_data->borderRadius > 0.0 )
+ painter->setClipPath( borderPath( rect() ), Qt::IntersectClip );
+ else
+ painter->setClipRect( contentsRect(), Qt::IntersectClip );
+ }
+
+ plot()->drawCanvas( painter );
+
+ painter->restore();
+
+ if ( withBackground && hackStyledBackground )
+ {
+ // Now paint the border on top
+ QStyleOptionFrame opt;
+ opt.initFrom(this);
+ style()->drawPrimitive( QStyle::PE_Frame, &opt, painter, this);
+ }
+}
+
+/*!
+ Draw the border of the plot canvas
+
+ \param painter Painter
+ \sa setBorderRadius(), QFrame::drawFrame()
+*/
+void QwtPlotCanvas::drawBorder( QPainter *painter )
+{
+ if ( d_data->borderRadius > 0 )
+ {
+ if ( frameWidth() > 0 )
+ {
+ QwtPainter::drawRoundedFrame( painter, QRectF( rect() ),
+ d_data->borderRadius, d_data->borderRadius,
+ palette(), frameWidth(), frameStyle() );
+ }
+ }
+ else
+ {
+ drawFrame( painter );
+ }
+}
+
+/*!
+ Resize event
+ \param event Resize event
+*/
+void QwtPlotCanvas::resizeEvent( QResizeEvent *event )
+{
+ QFrame::resizeEvent( event );
+ updateStyleSheetInfo();
+}
+
+/*!
+ Draw the focus indication
+ \param painter Painter
+*/
+void QwtPlotCanvas::drawFocusIndicator( QPainter *painter )
+{
+ const int margin = 1;
+
+ QRect focusRect = contentsRect();
+ focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin,
+ focusRect.width() - 2 * margin, focusRect.height() - 2 * margin );
+
+ QwtPainter::drawFocusRect( painter, this, focusRect );
+}
+
+/*!
+ Invalidate the paint cache and repaint the canvas
+ \sa invalidatePaintCache()
+*/
+void QwtPlotCanvas::replot()
+{
+ invalidateBackingStore();
+
+ if ( testPaintAttribute( QwtPlotCanvas::ImmediatePaint ) )
+ repaint( contentsRect() );
+ else
+ update( contentsRect() );
+}
+
+//! Update the cached informations about the current style sheet
+void QwtPlotCanvas::updateStyleSheetInfo()
+{
+ if ( !testAttribute(Qt::WA_StyledBackground ) )
+ return;
+
+ QwtStyleSheetRecorder recorder( size() );
+
+ QPainter painter( &recorder );
+
+ QStyleOption opt;
+ opt.initFrom(this);
+ style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this);
+
+ painter.end();
+
+ d_data->styleSheet.hasBorder = !recorder.border.rectList.isEmpty();
+ d_data->styleSheet.cornerRects = recorder.clipRects;
+
+ if ( recorder.background.path.isEmpty() )
+ {
+ if ( !recorder.border.rectList.isEmpty() )
+ {
+ d_data->styleSheet.borderPath =
+ qwtCombinePathList( rect(), recorder.border.pathList );
+ }
+ }
+ else
+ {
+ d_data->styleSheet.borderPath = recorder.background.path;
+ d_data->styleSheet.background.brush = recorder.background.brush;
+ d_data->styleSheet.background.origin = recorder.background.origin;
+ }
+}
+
+/*!
+ Calculate the painter path for a styled or rounded border
+
+ When the canvas has no styled background or rounded borders
+ the painter path is empty.
+
+ \param rect Bounding rectangle of the canvas
+ \return Painter path, that can be used for clipping
+*/
+QPainterPath QwtPlotCanvas::borderPath( const QRect &rect ) const
+{
+ if ( testAttribute(Qt::WA_StyledBackground ) )
+ {
+ QwtStyleSheetRecorder recorder( rect.size() );
+
+ QPainter painter( &recorder );
+
+ QStyleOption opt;
+ opt.initFrom(this);
+ opt.rect = rect;
+ style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this);
+
+ painter.end();
+
+ if ( !recorder.background.path.isEmpty() )
+ return recorder.background.path;
+
+ if ( !recorder.border.rectList.isEmpty() )
+ return qwtCombinePathList( rect, recorder.border.pathList );
+ }
+ else if ( d_data->borderRadius > 0.0 )
+ {
+ double fw2 = frameWidth() * 0.5;
+ QRectF r = QRectF(rect).adjusted( fw2, fw2, -fw2, -fw2 );
+
+ QPainterPath path;
+ path.addRoundedRect( r, d_data->borderRadius, d_data->borderRadius );
+ return path;
+ }
+
+ return QPainterPath();
+}
+
+/*!
+ Calculate a mask, that can be used to clip away the border frame
+
+ \param size Size including the frame
+*/
+QBitmap QwtPlotCanvas::borderMask( const QSize &size ) const
+{
+ const QRect r( 0, 0, size.width(), size.height() );
+
+ const QPainterPath path = borderPath( r );
+ if ( path.isEmpty() )
+ return QBitmap();
+
+ QImage image( size, QImage::Format_ARGB32_Premultiplied );
+ image.fill( Qt::color0 );
+
+ QPainter painter( &image );
+ painter.setClipPath( path );
+ painter.fillRect( r, Qt::color1 );
+
+ // now erase the frame
+
+ painter.setCompositionMode( QPainter::CompositionMode_DestinationOut );
+
+ if ( testAttribute(Qt::WA_StyledBackground ) )
+ {
+ QStyleOptionFrame opt;
+ opt.initFrom(this);
+ opt.rect = r;
+ style()->drawPrimitive( QStyle::PE_Frame, &opt, &painter, this );
+ }
+ else
+ {
+ if ( d_data->borderRadius > 0 && frameWidth() > 0 )
+ {
+ painter.setPen( QPen( Qt::color1, frameWidth() ) );
+ painter.setBrush( Qt::NoBrush );
+ painter.setRenderHint( QPainter::Antialiasing, true );
+
+ painter.drawPath( path );
+ }
+ }
+
+ painter.end();
+
+ const QImage mask = image.createMaskFromColor(
+ QColor( Qt::color1 ).rgb(), Qt::MaskOutColor );
+
+ return QBitmap::fromImage( mask );
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_canvas.h b/src/libpcp_qwt/src/qwt_plot_canvas.h
new file mode 100644
index 0000000..2f4c163
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_canvas.h
@@ -0,0 +1,171 @@
+/* -*- 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_PLOT_CANVAS_H
+#define QWT_PLOT_CANVAS_H
+
+#include "qwt_global.h"
+#include <qframe.h>
+#include <qpen.h>
+#include <qpainterpath.h>
+#include <qbitmap.h>
+
+class QwtPlot;
+class QPixmap;
+
+/*!
+ \brief Canvas of a QwtPlot.
+
+ Canvas is the widget where all plot items are displayed
+
+ \sa QwtPlot
+*/
+class QWT_EXPORT QwtPlotCanvas : public QFrame
+{
+ Q_OBJECT
+
+public:
+
+ /*!
+ \brief Paint attributes
+
+ The default setting enables BackingStore and Opaque.
+
+ \sa setPaintAttribute(), testPaintAttribute()
+ */
+ enum PaintAttribute
+ {
+ /*!
+ \brief Paint double buffered reusing the content
+ of the pixmap buffer when possible.
+
+ Using a backing store might improve the performance
+ significantly, when workin with widget overlays ( like rubberbands ).
+ Disabling the cache might improve the performance for
+ incremental paints (using QwtPlotDirectPainter ).
+
+ \sa backingStore(), invalidateBackingStore()
+ */
+ BackingStore = 1,
+
+ /*!
+ \brief Try to fill the complete contents rectangle
+ of the plot canvas
+
+ When using styled backgrounds Qt assumes, that the
+ canvas doesn't fill its area completely
+ ( f.e because of rounded borders ) and fills the area
+ below the canvas. When this is done with gradients it might
+ result in a serious performance bottleneck - depending on the size.
+
+ When the Opaque attribute is enabled the canvas tries to
+ identify the gaps with some heuristics and to fill those only.
+
+ \warning Will not work for semitransparent backgrounds
+ */
+ Opaque = 2,
+
+ /*!
+ \brief Try to improve painting of styled backgrounds
+
+ QwtPlotCanvas supports the box model attributes for
+ customizing the layout with style sheets. Unfortunately
+ the design of Qt style sheets has no concept how to
+ handle backgrounds with rounded corners - beside of padding.
+
+ When HackStyledBackground is enabled the plot canvas tries
+ to seperate the background from the background border
+ by reverse engeneering to paint the background before and
+ the border after the plot items. In this order the border
+ gets prefectly antialiased and you can avoid some pixel
+ artifacts in the corners.
+ */
+ HackStyledBackground = 4,
+
+ /*!
+ When ImmediatePaint is set replot() calls repaint()
+ instead of update().
+
+ \sa replot(), QWidget::repaint(), QWidget::update()
+ */
+ ImmediatePaint = 8
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ /*!
+ \brief Focus indicator
+ The default setting is NoFocusIndicator
+ \sa setFocusIndicator(), focusIndicator(), paintFocus()
+ */
+
+ enum FocusIndicator
+ {
+ //! Don't paint a focus indicator
+ NoFocusIndicator,
+
+ /*!
+ The focus is related to the complete canvas.
+ Paint the focus indicator using paintFocus()
+ */
+ CanvasFocusIndicator,
+
+ /*!
+ The focus is related to an item (curve, point, ...) on
+ the canvas. It is up to the application to display a
+ focus indication using f.e. highlighting.
+ */
+ ItemFocusIndicator
+ };
+
+ explicit QwtPlotCanvas( QwtPlot * );
+ virtual ~QwtPlotCanvas();
+
+ QwtPlot *plot();
+ const QwtPlot *plot() const;
+
+ void setFocusIndicator( FocusIndicator );
+ FocusIndicator focusIndicator() const;
+
+ void setBorderRadius( double );
+ double borderRadius() const;
+
+ QPainterPath borderPath( const QRect &rect ) const;
+ QBitmap borderMask( const QSize & ) const;
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ const QPixmap *backingStore() const;
+ void invalidateBackingStore();
+
+ void replot();
+
+ virtual bool event( QEvent * );
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ virtual void drawFocusIndicator( QPainter * );
+ virtual void drawBorder( QPainter * );
+
+ void updateStyleSheetInfo();
+
+private:
+ void drawCanvas( QPainter *, bool withBackground );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCanvas::PaintAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_curve.cpp b/src/libpcp_qwt/src/qwt_plot_curve.cpp
new file mode 100644
index 0000000..f5cc449
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_curve.cpp
@@ -0,0 +1,1127 @@
+/* -*- 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_plot_curve.h"
+#include "qwt_math.h"
+#include "qwt_clipper.h"
+#include "qwt_painter.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_scale_map.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_curve_fitter.h"
+#include "qwt_symbol.h"
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qalgorithms.h>
+#include <qmath.h>
+
+static int verifyRange( int size, int &i1, int &i2 )
+{
+ if ( size < 1 )
+ return 0;
+
+ i1 = qBound( 0, i1, size - 1 );
+ i2 = qBound( 0, i2, size - 1 );
+
+ if ( i1 > i2 )
+ qSwap( i1, i2 );
+
+ return ( i2 - i1 + 1 );
+}
+
+class QwtPlotCurve::PrivateData
+{
+public:
+ PrivateData():
+ style( QwtPlotCurve::Lines ),
+ baseline( 0.0 ),
+ symbol( NULL ),
+ attributes( 0 ),
+ paintAttributes( QwtPlotCurve::ClipPolygons ),
+ legendAttributes( 0 )
+ {
+ pen = QPen( Qt::black );
+ legendPen = Qt::NoPen;
+ curveFitter = new QwtSplineCurveFitter;
+ }
+
+ ~PrivateData()
+ {
+ delete symbol;
+ delete curveFitter;
+ }
+
+ QwtPlotCurve::CurveStyle style;
+ double baseline;
+
+ const QwtSymbol *symbol;
+ QwtCurveFitter *curveFitter;
+
+ QPen pen;
+ QPen legendPen;
+ QBrush brush;
+
+ QwtPlotCurve::CurveAttributes attributes;
+ QwtPlotCurve::PaintAttributes paintAttributes;
+
+ QwtPlotCurve::LegendAttributes legendAttributes;
+};
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotCurve::QwtPlotCurve( const QwtText &title ):
+ QwtPlotSeriesItem<QPointF>( title )
+{
+ init();
+}
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotCurve::QwtPlotCurve( const QString &title ):
+ QwtPlotSeriesItem<QPointF>( QwtText( title ) )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotCurve::~QwtPlotCurve()
+{
+ delete d_data;
+}
+
+//! Initialize internal members
+void QwtPlotCurve::init()
+{
+ setItemAttribute( QwtPlotItem::Legend );
+ setItemAttribute( QwtPlotItem::AutoScale );
+
+ d_data = new PrivateData;
+ d_series = new QwtPointSeriesData();
+
+ setZ( 20.0 );
+}
+
+//! \return QwtPlotItem::Rtti_PlotCurve
+int QwtPlotCurve::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotCurve;
+}
+
+/*!
+ Specify an attribute how to draw the curve
+
+ \param attribute Paint attribute
+ \param on On/Off
+ \sa testPaintAttribute()
+*/
+void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+}
+
+/*!
+ \brief Return the current paint attributes
+ \sa setPaintAttribute()
+*/
+bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const
+{
+ return ( d_data->paintAttributes & attribute );
+}
+
+/*!
+ Specify an attribute how to draw the legend identifier
+
+ \param attribute Attribute
+ \param on On/Off
+ /sa testLegendAttribute()
+*/
+void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->legendAttributes |= attribute;
+ else
+ d_data->legendAttributes &= ~attribute;
+}
+
+/*!
+ \brief Return the current paint attributes
+ \sa setLegendAttribute()
+*/
+bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const
+{
+ return ( d_data->legendAttributes & attribute );
+}
+
+/*!
+ Set the curve's drawing style
+
+ \param style Curve style
+ \sa style()
+*/
+void QwtPlotCurve::setStyle( CurveStyle style )
+{
+ if ( style != d_data->style )
+ {
+ d_data->style = style;
+ itemChanged();
+ }
+}
+
+/*!
+ Return the current style
+ \sa setStyle()
+*/
+QwtPlotCurve::CurveStyle QwtPlotCurve::style() const
+{
+ return d_data->style;
+}
+
+/*!
+ Assign a symbol
+
+ The curve will take the ownership of the symbol, hence the previously
+ set symbol will be delete by setting a new one. If \p symbol is
+ \c NULL no symbol will be drawn.
+
+ \param symbol Symbol
+ \sa symbol()
+*/
+void QwtPlotCurve::setSymbol( const QwtSymbol *symbol )
+{
+ if ( symbol != d_data->symbol )
+ {
+ delete d_data->symbol;
+ d_data->symbol = symbol;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Current symbol or NULL, when no symbol has been assigned
+ \sa setSymbol()
+*/
+const QwtSymbol *QwtPlotCurve::symbol() const
+{
+ return d_data->symbol;
+}
+
+/*!
+ Assign a pen
+
+ \param pen New pen
+ \sa pen(), brush()
+*/
+void QwtPlotCurve::setPen( const QPen &pen )
+{
+ if ( pen != d_data->pen )
+ {
+ d_data->pen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Pen used to draw the lines
+ \sa setPen(), brush()
+*/
+const QPen& QwtPlotCurve::pen() const
+{
+ return d_data->pen;
+}
+
+/*!
+ \brief Assign a brush.
+
+ In case of brush.style() != QBrush::NoBrush
+ and style() != QwtPlotCurve::Sticks
+ the area between the curve and the baseline will be filled.
+
+ In case !brush.color().isValid() the area will be filled by
+ pen.color(). The fill algorithm simply connects the first and the
+ last curve point to the baseline. So the curve data has to be sorted
+ (ascending or descending).
+
+ \param brush New brush
+ \sa brush(), setBaseline(), baseline()
+*/
+void QwtPlotCurve::setBrush( const QBrush &brush )
+{
+ if ( brush != d_data->brush )
+ {
+ d_data->brush = brush;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Brush used to fill the area between lines and the baseline
+ \sa setBrush(), setBaseline(), baseline()
+*/
+const QBrush& QwtPlotCurve::brush() const
+{
+ return d_data->brush;
+}
+
+/*!
+ Draw an interval of the curve
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first point to be painted
+ \param to Index of the last point to be painted. If to < 0 the
+ curve will be painted to its last point.
+
+ \sa drawCurve(), drawSymbols(),
+*/
+void QwtPlotCurve::drawSeries( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ if ( !painter || dataSize() <= 0 )
+ return;
+
+ if ( to < 0 )
+ to = dataSize() - 1;
+
+ if ( verifyRange( dataSize(), from, to ) > 0 )
+ {
+ painter->save();
+ painter->setPen( d_data->pen );
+
+ /*
+ Qt 4.0.0 is slow when drawing lines, but it's even
+ slower when the painter has a brush. So we don't
+ set the brush before we really need it.
+ */
+
+ drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to );
+ painter->restore();
+
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
+ {
+ painter->save();
+ drawSymbols( painter, *d_data->symbol,
+ xMap, yMap, canvasRect, from, to );
+ painter->restore();
+ }
+ }
+}
+
+/*!
+ \brief Draw the line part (without symbols) of a curve interval.
+ \param painter Painter
+ \param style curve style, see QwtPlotCurve::CurveStyle
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from index of the first point to be painted
+ \param to index of the last point to be painted
+ \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks()
+*/
+void QwtPlotCurve::drawCurve( QPainter *painter, int style,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ switch ( style )
+ {
+ case Lines:
+ if ( testCurveAttribute( Fitted ) )
+ {
+ // we always need the complete
+ // curve for fitting
+ from = 0;
+ to = dataSize() - 1;
+ }
+ drawLines( painter, xMap, yMap, canvasRect, from, to );
+ break;
+ case Sticks:
+ drawSticks( painter, xMap, yMap, canvasRect, from, to );
+ break;
+ case Steps:
+ drawSteps( painter, xMap, yMap, canvasRect, from, to );
+ break;
+ case Dots:
+ drawDots( painter, xMap, yMap, canvasRect, from, to );
+ break;
+ case NoCurve:
+ default:
+ break;
+ }
+}
+
+/*!
+ \brief Draw lines
+
+ If the CurveAttribute Fitted is enabled a QwtCurveFitter tries
+ to interpolate/smooth the curve, before it is painted.
+
+ \param painter Painter
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from index of the first point to be painted
+ \param to index of the last point to be painted
+
+ \sa setCurveAttribute(), setCurveFitter(), draw(),
+ drawLines(), drawDots(), drawSteps(), drawSticks()
+*/
+void QwtPlotCurve::drawLines( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ int size = to - from + 1;
+ if ( size <= 0 )
+ return;
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ QPolygonF polyline( size );
+
+ QPointF *points = polyline.data();
+ for ( int i = from; i <= to; i++ )
+ {
+ const QPointF sample = d_series->sample( i );
+
+ double x = xMap.transform( sample.x() );
+ double y = yMap.transform( sample.y() );
+ if ( doAlign )
+ {
+ x = qRound( x );
+ y = qRound( y );
+ }
+
+ points[i - from].rx() = x;
+ points[i - from].ry() = y;
+ }
+
+ if ( ( d_data->attributes & Fitted ) && d_data->curveFitter )
+ polyline = d_data->curveFitter->fitCurve( polyline );
+
+ if ( d_data->paintAttributes & ClipPolygons )
+ {
+ qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
+ const QPolygonF clipped = QwtClipper::clipPolygonF(
+ canvasRect.adjusted(-pw, -pw, pw, pw), polyline, false );
+
+ QwtPainter::drawPolyline( painter, clipped );
+ }
+ else
+ {
+ QwtPainter::drawPolyline( painter, polyline );
+ }
+
+ if ( d_data->brush.style() != Qt::NoBrush )
+ fillCurve( painter, xMap, yMap, canvasRect, polyline );
+}
+
+/*!
+ Draw sticks
+
+ \param painter Painter
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from index of the first point to be painted
+ \param to index of the last point to be painted
+
+ \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps()
+*/
+void QwtPlotCurve::drawSticks( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &, int from, int to ) const
+{
+ painter->save();
+ painter->setRenderHint( QPainter::Antialiasing, false );
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ double x0 = xMap.transform( d_data->baseline );
+ double y0 = yMap.transform( d_data->baseline );
+ if ( doAlign )
+ {
+ x0 = qRound( x0 );
+ y0 = qRound( y0 );
+ }
+
+ const Qt::Orientation o = orientation();
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QPointF sample = d_series->sample( i );
+ double xi = xMap.transform( sample.x() );
+ double yi = yMap.transform( sample.y() );
+ if ( doAlign )
+ {
+ xi = qRound( xi );
+ yi = qRound( yi );
+ }
+
+ if ( o == Qt::Horizontal )
+ QwtPainter::drawLine( painter, x0, yi, xi, yi );
+ else
+ QwtPainter::drawLine( painter, xi, y0, xi, yi );
+ }
+
+ painter->restore();
+}
+
+/*!
+ Draw dots
+
+ \param painter Painter
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from index of the first point to be painted
+ \param to index of the last point to be painted
+
+ \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
+*/
+void QwtPlotCurve::drawDots( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ const bool doFill = d_data->brush.style() != Qt::NoBrush;
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ QPolygonF polyline;
+ if ( doFill )
+ polyline.resize( to - from + 1 );
+
+ QPointF *points = polyline.data();
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QPointF sample = d_series->sample( i );
+ double xi = xMap.transform( sample.x() );
+ double yi = yMap.transform( sample.y() );
+ if ( doAlign )
+ {
+ xi = qRound( xi );
+ yi = qRound( yi );
+ }
+
+ QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
+
+ if ( doFill )
+ {
+ points[i - from].rx() = xi;
+ points[i - from].ry() = yi;
+ }
+ }
+
+ if ( doFill )
+ fillCurve( painter, xMap, yMap, canvasRect, polyline );
+}
+
+/*!
+ Draw step function
+
+ The direction of the steps depends on Inverted attribute.
+
+ \param painter Painter
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from index of the first point to be painted
+ \param to index of the last point to be painted
+
+ \sa CurveAttribute, setCurveAttribute(),
+ draw(), drawCurve(), drawDots(), drawLines(), drawSticks()
+*/
+void QwtPlotCurve::drawSteps( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ QPolygonF polygon( 2 * ( to - from ) + 1 );
+ QPointF *points = polygon.data();
+
+ bool inverted = orientation() == Qt::Vertical;
+ if ( d_data->attributes & Inverted )
+ inverted = !inverted;
+
+ int i, ip;
+ for ( i = from, ip = 0; i <= to; i++, ip += 2 )
+ {
+ const QPointF sample = d_series->sample( i );
+ double xi = xMap.transform( sample.x() );
+ double yi = yMap.transform( sample.y() );
+ if ( doAlign )
+ {
+ xi = qRound( xi );
+ yi = qRound( yi );
+ }
+
+ if ( ip > 0 )
+ {
+ const QPointF &p0 = points[ip - 2];
+ QPointF &p = points[ip - 1];
+
+ if ( inverted )
+ {
+ p.rx() = p0.x();
+ p.ry() = yi;
+ }
+ else
+ {
+ p.rx() = xi;
+ p.ry() = p0.y();
+ }
+ }
+
+ points[ip].rx() = xi;
+ points[ip].ry() = yi;
+ }
+
+ if ( d_data->paintAttributes & ClipPolygons )
+ {
+ const QPolygonF clipped = QwtClipper::clipPolygonF(
+ canvasRect, polygon, false );
+
+ QwtPainter::drawPolyline( painter, clipped );
+ }
+ else
+ {
+ QwtPainter::drawPolyline( painter, polygon );
+ }
+
+ if ( d_data->brush.style() != Qt::NoBrush )
+ fillCurve( painter, xMap, yMap, canvasRect, polygon );
+}
+
+
+/*!
+ Specify an attribute for drawing the curve
+
+ \param attribute Curve attribute
+ \param on On/Off
+
+ /sa testCurveAttribute(), setCurveFitter()
+*/
+void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on )
+{
+ if ( bool( d_data->attributes & attribute ) == on )
+ return;
+
+ if ( on )
+ d_data->attributes |= attribute;
+ else
+ d_data->attributes &= ~attribute;
+
+ itemChanged();
+}
+
+/*!
+ \return true, if attribute is enabled
+ \sa setCurveAttribute()
+*/
+bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const
+{
+ return d_data->attributes & attribute;
+}
+
+/*!
+ Assign a curve fitter
+
+ The curve fitter "smooths" the curve points, when the Fitted
+ CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting.
+
+ The curve fitter operates on the translated points ( = widget coordinates)
+ to be functional for logarithmic scales. Obviously this is less performant
+ for fitting algorithms, that reduce the number of points.
+
+ For situations, where curve fitting is used to improve the performance
+ of painting huge series of points it might be better to execute the fitter
+ on the curve points once and to cache the result in the QwtSeriesData object.
+
+ \param curveFitter() Curve fitter
+ \sa Fitted
+*/
+void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter )
+{
+ delete d_data->curveFitter;
+ d_data->curveFitter = curveFitter;
+
+ itemChanged();
+}
+
+/*!
+ Get the curve fitter. If curve fitting is disabled NULL is returned.
+
+ \return Curve fitter
+ \sa setCurveFitter(), Fitted
+*/
+QwtCurveFitter *QwtPlotCurve::curveFitter() const
+{
+ return d_data->curveFitter;
+}
+
+/*!
+ Fill the area between the curve and the baseline with
+ the curve brush
+
+ \param painter Painter
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param polygon Polygon - will be modified !
+
+ \sa setBrush(), setBaseline(), setStyle()
+*/
+void QwtPlotCurve::fillCurve( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, QPolygonF &polygon ) const
+{
+ if ( d_data->brush.style() == Qt::NoBrush )
+ return;
+
+ closePolyline( painter, xMap, yMap, polygon );
+ if ( polygon.count() <= 2 ) // a line can't be filled
+ return;
+
+ QBrush brush = d_data->brush;
+ if ( !brush.color().isValid() )
+ brush.setColor( d_data->pen.color() );
+
+ if ( d_data->paintAttributes & ClipPolygons )
+ polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true );
+
+ painter->save();
+
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( brush );
+
+ QwtPainter::drawPolygon( painter, polygon );
+
+ painter->restore();
+}
+
+/*!
+ \brief Complete a polygon to be a closed polygon including the
+ area between the original polygon and the baseline.
+
+ \param painter Painter
+ \param xMap X map
+ \param yMap Y map
+ \param polygon Polygon to be completed
+*/
+void QwtPlotCurve::closePolyline( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ QPolygonF &polygon ) const
+{
+ if ( polygon.size() < 2 )
+ return;
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ double baseline = d_data->baseline;
+
+ if ( orientation() == Qt::Vertical )
+ {
+ if ( yMap.transformation()->type() == QwtScaleTransformation::Log10 )
+ {
+ if ( baseline < QwtScaleMap::LogMin )
+ baseline = QwtScaleMap::LogMin;
+ }
+
+ double refY = yMap.transform( baseline );
+ if ( doAlign )
+ refY = qRound( refY );
+
+ polygon += QPointF( polygon.last().x(), refY );
+ polygon += QPointF( polygon.first().x(), refY );
+ }
+ else
+ {
+ if ( xMap.transformation()->type() == QwtScaleTransformation::Log10 )
+ {
+ if ( baseline < QwtScaleMap::LogMin )
+ baseline = QwtScaleMap::LogMin;
+ }
+
+ double refX = xMap.transform( baseline );
+ if ( doAlign )
+ refX = qRound( refX );
+
+ polygon += QPointF( refX, polygon.last().y() );
+ polygon += QPointF( refX, polygon.first().y() );
+ }
+}
+
+/*!
+ Draw symbols
+
+ \param painter Painter
+ \param symbol Curve symbol
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first point to be painted
+ \param to Index of the last point to be painted
+
+ \sa setSymbol(), drawSeries(), drawCurve()
+*/
+void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ bool usePixmap = testPaintAttribute( CacheSymbols );
+ if ( usePixmap && !doAlign )
+ {
+ // Don't use the pixmap, when the paint device
+ // could generate scalable vectors
+
+ usePixmap = false;
+ }
+
+ if ( usePixmap )
+ {
+ const QSize sz = ( 2 * symbol.boundingSize() + QSize( 1, 1 ) ) / 2;
+ const int w2 = sz.width() / 2;
+ const int h2 = sz.height() / 2;
+
+ QPixmap pm( sz );
+ pm.fill( Qt::transparent );
+
+ QPainter p( &pm );
+ p.setRenderHints( painter->renderHints() );
+ symbol.drawSymbol( &p, QPointF( w2, h2 ) );
+ p.end();
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QPointF sample = d_series->sample( i );
+
+ const double xi = xMap.transform( sample.x() );
+ const double yi = yMap.transform( sample.y() );
+
+ if ( canvasRect.contains( xi, yi ) )
+ {
+ const int left = qRound( xi ) - w2;
+ const int top = qRound( yi ) - h2;
+
+ painter->drawPixmap( left, top, pm );
+ }
+ }
+ }
+ else
+ {
+ const int chunkSize = 500;
+
+ for ( int i = from; i <= to; i += chunkSize )
+ {
+ const int n = qMin( chunkSize, to - i + 1 );
+
+ QPolygonF points;
+ for ( int j = 0; j < n; j++ )
+ {
+ const QPointF sample = d_series->sample( i + j );
+
+ const double xi = xMap.transform( sample.x() );
+ const double yi = yMap.transform( sample.y() );
+
+ if ( canvasRect.contains( xi, yi ) )
+ points += QPointF( xi, yi );
+ }
+
+ if ( points.size() > 0 )
+ symbol.drawSymbols( painter, points );
+ }
+ }
+}
+
+/*!
+ \brief Set the value of the baseline
+
+ The baseline is needed for filling the curve with a brush or
+ the Sticks drawing style.
+
+ The interpretation of the baseline depends on the orientation().
+ With Qt::Horizontal, the baseline is interpreted as a horizontal line
+ at y = baseline(), with Qt::Vertical, it is interpreted as a vertical
+ line at x = baseline().
+
+ The default value is 0.0.
+
+ \param value Value of the baseline
+ \sa baseline(), setBrush(), setStyle(), QwtPlotAbstractSeriesItem::orientation()
+*/
+void QwtPlotCurve::setBaseline( double value )
+{
+ if ( d_data->baseline != value )
+ {
+ d_data->baseline = value;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Value of the baseline
+ \sa setBaseline()
+*/
+double QwtPlotCurve::baseline() const
+{
+ return d_data->baseline;
+}
+
+/*!
+ Find the closest curve point for a specific position
+
+ \param pos Position, where to look for the closest curve point
+ \param dist If dist != NULL, closestPoint() returns the distance between
+ the position and the clostest curve point
+ \return Index of the closest curve point, or -1 if none can be found
+ ( f.e when the curve has no points )
+ \note closestPoint() implements a dumb algorithm, that iterates
+ over all points
+*/
+int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const
+{
+ if ( plot() == NULL || dataSize() <= 0 )
+ return -1;
+
+ const QwtScaleMap xMap = plot()->canvasMap( xAxis() );
+ const QwtScaleMap yMap = plot()->canvasMap( yAxis() );
+
+ int index = -1;
+ double dmin = 1.0e10;
+
+ for ( uint i = 0; i < dataSize(); i++ )
+ {
+ const QPointF sample = d_series->sample( i );
+
+ const double cx = xMap.transform( sample.x() ) - pos.x();
+ const double cy = yMap.transform( sample.y() ) - pos.y();
+
+ const double f = qwtSqr( cx ) + qwtSqr( cy );
+ if ( f < dmin )
+ {
+ index = i;
+ dmin = f;
+ }
+ }
+ if ( dist )
+ *dist = qSqrt( dmin );
+
+ return index;
+}
+
+/*!
+ \brief Update the widget that represents the item on the legend
+
+ \param legend Legend
+ \sa drawLegendIdentifier(), legendItem(), QwtPlotItem::Legend
+*/
+void QwtPlotCurve::updateLegend( QwtLegend *legend ) const
+{
+ if ( legend && testItemAttribute( QwtPlotItem::Legend )
+ && ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
+ && d_data->symbol
+ && d_data->symbol->style() != QwtSymbol::NoSymbol )
+ {
+ QWidget *lgdItem = legend->find( this );
+ if ( lgdItem == NULL )
+ {
+ lgdItem = legendItem();
+ if ( lgdItem )
+ legend->insert( this, lgdItem );
+ }
+
+ QwtLegendItem *l = qobject_cast<QwtLegendItem *>( lgdItem );
+ if ( l )
+ {
+ QSize sz = d_data->symbol->boundingSize();
+ sz += QSize( 2, 2 ); // margin
+
+ if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
+ {
+ // Avoid, that the line is completely covered by the symbol
+
+ int w = qCeil( 1.5 * sz.width() );
+ if ( w % 2 )
+ w++;
+
+ sz.setWidth( qMax( 8, w ) );
+ }
+
+ l->setIdentifierSize( sz );
+ }
+ }
+
+ QwtPlotItem::updateLegend( legend );
+}
+
+/*!
+ \brief Draw the identifier representing the curve on the legend
+
+ \param painter Painter
+ \param rect Bounding rectangle for the identifier
+
+ \sa setLegendAttribute(), QwtPlotItem::Legend
+*/
+void QwtPlotCurve::drawLegendIdentifier(
+ QPainter *painter, const QRectF &rect ) const
+{
+ if ( rect.isEmpty() )
+ return;
+
+ const double dim = qMin( rect.width(), rect.height() );
+
+ QSizeF size( dim, dim );
+
+ QRectF r( 0, 0, size.width(), size.height() );
+ r.moveCenter( rect.center() );
+
+ if ( d_data->legendAttributes == 0 )
+ {
+ QBrush brush = d_data->brush;
+ if ( brush.style() == Qt::NoBrush )
+ {
+ if ( style() != QwtPlotCurve::NoCurve )
+ brush = QBrush( pen().color() );
+ else if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
+ {
+ brush = QBrush( d_data->symbol->pen().color() );
+ }
+ }
+ if ( brush.style() != Qt::NoBrush )
+ painter->fillRect( r, brush );
+ }
+ if ( d_data->legendAttributes & QwtPlotCurve::LegendShowBrush )
+ {
+ if ( d_data->brush.style() != Qt::NoBrush )
+ painter->fillRect( r, d_data->brush );
+ }
+ if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine )
+ {
+ if ( pen() != Qt::NoPen )
+ {
+ painter->setPen( pen() );
+ QwtPainter::drawLine( painter, rect.left(), rect.center().y(),
+ rect.right() - 1.0, rect.center().y() );
+ }
+ }
+ if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol )
+ {
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
+ {
+ QSize symbolSize = d_data->symbol->boundingSize();
+ symbolSize -= QSize( 2, 2 );
+
+ // scale the symbol size down if it doesn't fit into rect.
+
+ double xRatio = 1.0;
+ if ( rect.width() < symbolSize.width() )
+ xRatio = rect.width() / symbolSize.width();
+ double yRatio = 1.0;
+ if ( rect.height() < symbolSize.height() )
+ yRatio = rect.height() / symbolSize.height();
+
+ const double ratio = qMin( xRatio, yRatio );
+
+ painter->save();
+ painter->scale( ratio, ratio );
+
+ d_data->symbol->drawSymbol( painter, rect.center() / ratio );
+
+ painter->restore();
+ }
+ }
+}
+
+/*!
+ Initialize data with an array of points (explicitly shared).
+
+ \param samples Vector of points
+*/
+void QwtPlotCurve::setSamples( const QVector<QPointF> &samples )
+{
+ delete d_series;
+ d_series = new QwtPointSeriesData( samples );
+ itemChanged();
+}
+
+#ifndef QWT_NO_COMPAT
+
+/*!
+ \brief Initialize the data by pointing to memory blocks which
+ are not managed by QwtPlotCurve.
+
+ setRawSamples is provided for efficiency.
+ It is important to keep the pointers
+ during the lifetime of the underlying QwtCPointerData class.
+
+ \param xData pointer to x data
+ \param yData pointer to y data
+ \param size size of x and y
+
+ \sa QwtCPointerData
+*/
+void QwtPlotCurve::setRawSamples(
+ const double *xData, const double *yData, int size )
+{
+ delete d_series;
+ d_series = new QwtCPointerData( xData, yData, size );
+ itemChanged();
+}
+
+/*!
+ Set data by copying x- and y-values from specified memory blocks.
+ Contrary to setRawSamples(), this function makes a 'deep copy' of
+ the data.
+
+ \param xData pointer to x values
+ \param yData pointer to y values
+ \param size size of xData and yData
+
+ \sa QwtPointArrayData
+*/
+void QwtPlotCurve::setSamples(
+ const double *xData, const double *yData, int size )
+{
+ delete d_series;
+ d_series = new QwtPointArrayData( xData, yData, size );
+ itemChanged();
+}
+
+/*!
+ \brief Initialize data with x- and y-arrays (explicitly shared)
+
+ \param xData x data
+ \param yData y data
+
+ \sa QwtPointArrayData
+*/
+void QwtPlotCurve::setSamples( const QVector<double> &xData,
+ const QVector<double> &yData )
+{
+ delete d_series;
+ d_series = new QwtPointArrayData( xData, yData );
+ itemChanged();
+}
+#endif // !QWT_NO_COMPAT
+
diff --git a/src/libpcp_qwt/src/qwt_plot_curve.h b/src/libpcp_qwt/src/qwt_plot_curve.h
new file mode 100644
index 0000000..a957c4b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_curve.h
@@ -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
+ *****************************************************************************/
+
+#ifndef QWT_PLOT_CURVE_H
+#define QWT_PLOT_CURVE_H
+
+#include "qwt_global.h"
+#include "qwt_plot_seriesitem.h"
+#include "qwt_series_data.h"
+#include "qwt_text.h"
+#include <qpen.h>
+#include <qstring.h>
+
+class QPainter;
+class QPolygonF;
+class QwtScaleMap;
+class QwtSymbol;
+class QwtCurveFitter;
+
+/*!
+ \brief A plot item, that represents a series of points
+
+ A curve is the representation of a series of points in the x-y plane.
+ It supports different display styles, interpolation ( f.e. spline )
+ and symbols.
+
+ \par Usage
+ <dl><dt>a) Assign curve properties</dt>
+ <dd>When a curve is created, it is configured to draw black solid lines
+ with in QwtPlotCurve::Lines style and no symbols.
+ You can change this by calling
+ setPen(), setStyle() and setSymbol().</dd>
+ <dt>b) Connect/Assign data.</dt>
+ <dd>QwtPlotCurve gets its points using a QwtSeriesData object offering
+ a bridge to the real storage of the points ( like QAbstractItemModel ).
+ There are several convenience classes derived from QwtSeriesData, that also store
+ the points inside ( like QStandardItemModel ). QwtPlotCurve also offers
+ a couple of variations of setSamples(), that build QwtSeriesData objects from
+ arrays internally.</dd>
+ <dt>c) Attach the curve to a plot</dt>
+ <dd>See QwtPlotItem::attach()
+ </dd></dl>
+
+ \par Example:
+ see examples/bode
+
+ \sa QwtPointSeriesData, QwtSymbol, QwtScaleMap
+*/
+class QWT_EXPORT QwtPlotCurve: public QwtPlotSeriesItem<QPointF>
+{
+public:
+ /*!
+ Curve styles.
+ \sa setStyle(), style()
+ */
+ enum CurveStyle
+ {
+ /*!
+ Don't draw a curve. Note: This doesn't affect the symbols.
+ */
+ NoCurve = -1,
+
+ /*!
+ Connect the points with straight lines. The lines might
+ be interpolated depending on the 'Fitted' attribute. Curve
+ fitting can be configured using setCurveFitter().
+ */
+ Lines,
+
+ /*!
+ Draw vertical or horizontal sticks ( depending on the
+ orientation() ) from a baseline which is defined by setBaseline().
+ */
+ Sticks,
+
+ /*!
+ Connect the points with a step function. The step function
+ is drawn from the left to the right or vice versa,
+ depending on the QwtPlotCurve::Inverted attribute.
+ */
+ Steps,
+
+ /*!
+ Draw dots at the locations of the data points. Note:
+ This is different from a dotted line (see setPen()), and faster
+ as a curve in QwtPlotCurve::NoStyle style and a symbol
+ painting a point.
+ */
+ Dots,
+
+ /*!
+ Styles >= QwtPlotCurve::UserCurve are reserved for derived
+ classes of QwtPlotCurve that overload drawCurve() with
+ additional application specific curve types.
+ */
+ UserCurve = 100
+ };
+
+ /*!
+ Attribute for drawing the curve
+ \sa setCurveAttribute(), testCurveAttribute(), curveFitter()
+ */
+ enum CurveAttribute
+ {
+ /*!
+ For QwtPlotCurve::Steps only.
+ Draws a step function from the right to the left.
+ */
+ Inverted = 0x01,
+
+ /*!
+ Only in combination with QwtPlotCurve::Lines
+ A QwtCurveFitter tries to
+ interpolate/smooth the curve, before it is painted.
+
+ \note Curve fitting requires temorary memory
+ for calculating coefficients and additional points.
+ If painting in QwtPlotCurve::Fitted mode is slow it might be better
+ to fit the points, before they are passed to QwtPlotCurve.
+ */
+ Fitted = 0x02
+ };
+
+ //! Curve attributes
+ typedef QFlags<CurveAttribute> CurveAttributes;
+
+ /*!
+ Attributes how to represent the curve on the legend
+
+ \sa setLegendAttribute(), testLegendAttribute(),
+ drawLegendIdentifier()
+ */
+
+ enum LegendAttribute
+ {
+ /*!
+ QwtPlotCurve tries to find a color representing the curve
+ and paints a rectangle with it.
+ */
+ LegendNoAttribute = 0x00,
+
+ /*!
+ If the style() is not QwtPlotCurve::NoCurve a line
+ is painted with the curve pen().
+ */
+ LegendShowLine = 0x01,
+
+ /*!
+ If the curve has a valid symbol it is painted.
+ */
+ LegendShowSymbol = 0x02,
+
+ /*!
+ If the curve has a brush a rectangle filled with the
+ curve brush() is painted.
+ */
+ LegendShowBrush = 0x04
+ };
+
+ //! Legend attributes
+ typedef QFlags<LegendAttribute> LegendAttributes;
+
+ /*!
+ Attributes to modify the drawing algorithm.
+ The default setting enables ClipPolygons
+
+ \sa setPaintAttribute(), testPaintAttribute()
+ */
+ enum PaintAttribute
+ {
+ /*!
+ Clip polygons before painting them. In situations, where points
+ are far outside the visible area (f.e when zooming deep) this
+ might be a substantial improvement for the painting performance
+ */
+ ClipPolygons = 0x01,
+
+ /*!
+ Paint the symbol to a QPixmap and paint the pixmap
+ instead rendering the symbol for each point. The flag has
+ no effect, when the curve is not painted to the canvas
+ ( f.e when exporting the plot to a PDF document ).
+ */
+ CacheSymbols = 0x02
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ explicit QwtPlotCurve( const QString &title = QString::null );
+ explicit QwtPlotCurve( const QwtText &title );
+
+ virtual ~QwtPlotCurve();
+
+ virtual int rtti() const;
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ void setLegendAttribute( LegendAttribute, bool on = true );
+ bool testLegendAttribute( LegendAttribute ) const;
+
+#ifndef QWT_NO_COMPAT
+ void setRawSamples( const double *xData, const double *yData, int size );
+ void setSamples( const double *xData, const double *yData, int size );
+ void setSamples( const QVector<double> &xData, const QVector<double> &yData );
+#endif
+ void setSamples( const QVector<QPointF> & );
+
+ int closestPoint( const QPoint &pos, double *dist = NULL ) const;
+
+ double minXValue() const;
+ double maxXValue() const;
+ double minYValue() const;
+ double maxYValue() const;
+
+ void setCurveAttribute( CurveAttribute, bool on = true );
+ bool testCurveAttribute( CurveAttribute ) const;
+
+ void setPen( const QPen & );
+ const QPen &pen() const;
+
+ void setBrush( const QBrush & );
+ const QBrush &brush() const;
+
+ void setBaseline( double ref );
+ double baseline() const;
+
+ void setStyle( CurveStyle style );
+ CurveStyle style() const;
+
+ void setSymbol( const QwtSymbol *s );
+ const QwtSymbol *symbol() const;
+
+ void setCurveFitter( QwtCurveFitter * );
+ QwtCurveFitter *curveFitter() const;
+
+ virtual void drawSeries( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual void updateLegend( QwtLegend * ) const;
+ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const;
+
+protected:
+
+ void init();
+
+ virtual void drawCurve( QPainter *, int style,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual void drawSymbols( QPainter *, const QwtSymbol &,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ void drawLines( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ void drawSticks( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ void drawDots( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ void drawSteps( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual void fillCurve( QPainter *,
+ const QwtScaleMap &, const QwtScaleMap &,
+ const QRectF &canvasRect, QPolygonF & ) const;
+
+ void closePolyline( QPainter *,
+ const QwtScaleMap &, const QwtScaleMap &, QPolygonF & ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+//! boundingRect().left()
+inline double QwtPlotCurve::minXValue() const
+{
+ return boundingRect().left();
+}
+
+//! boundingRect().right()
+inline double QwtPlotCurve::maxXValue() const
+{
+ return boundingRect().right();
+}
+
+//! boundingRect().top()
+inline double QwtPlotCurve::minYValue() const
+{
+ return boundingRect().top();
+}
+
+//! boundingRect().bottom()
+inline double QwtPlotCurve::maxYValue() const
+{
+ return boundingRect().bottom();
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::PaintAttributes )
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::LegendAttributes )
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::CurveAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_dict.cpp b/src/libpcp_qwt/src/qwt_plot_dict.cpp
new file mode 100644
index 0000000..4125137
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_dict.cpp
@@ -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
+ *****************************************************************************/
+
+#include "qwt_plot_dict.h"
+
+class QwtPlotDict::PrivateData
+{
+public:
+
+ class ItemList: public QList<QwtPlotItem *>
+ {
+ public:
+ void insertItem( QwtPlotItem *item )
+ {
+ if ( item == NULL )
+ return;
+
+ QList<QwtPlotItem *>::iterator it =
+ qUpperBound( begin(), end(), item, LessZThan() );
+ insert( it, item );
+ }
+
+ void removeItem( QwtPlotItem *item )
+ {
+ if ( item == NULL )
+ return;
+
+ QList<QwtPlotItem *>::iterator it =
+ qLowerBound( begin(), end(), item, LessZThan() );
+
+ for ( ; it != end(); ++it )
+ {
+ if ( item == *it )
+ {
+ erase( it );
+ break;
+ }
+ }
+ }
+ private:
+ class LessZThan
+ {
+ public:
+ inline bool operator()( const QwtPlotItem *item1,
+ const QwtPlotItem *item2 ) const
+ {
+ return item1->z() < item2->z();
+ }
+ };
+ };
+
+ ItemList itemList;
+ bool autoDelete;
+};
+
+/*!
+ Constructor
+
+ Auto deletion is enabled.
+ \sa setAutoDelete(), attachItem()
+*/
+QwtPlotDict::QwtPlotDict()
+{
+ d_data = new QwtPlotDict::PrivateData;
+ d_data->autoDelete = true;
+}
+
+/*!
+ Destructor
+
+ If autoDelete is on, all attached items will be deleted
+ \sa setAutoDelete(), autoDelete(), attachItem()
+*/
+QwtPlotDict::~QwtPlotDict()
+{
+ detachItems( QwtPlotItem::Rtti_PlotItem, d_data->autoDelete );
+ delete d_data;
+}
+
+/*!
+ En/Disable Auto deletion
+
+ If Auto deletion is on all attached plot items will be deleted
+ in the destructor of QwtPlotDict. The default value is on.
+
+ \sa autoDelete(), attachItem()
+*/
+void QwtPlotDict::setAutoDelete( bool autoDelete )
+{
+ d_data->autoDelete = autoDelete;
+}
+
+/*!
+ \return true if auto deletion is enabled
+ \sa setAutoDelete(), attachItem()
+*/
+bool QwtPlotDict::autoDelete() const
+{
+ return d_data->autoDelete;
+}
+
+/*!
+ Attach/Detach a plot item
+
+ Attached items will be deleted in the destructor,
+ if auto deletion is enabled (default). Manually detached
+ items are not deleted.
+
+ \param item Plot item to attach/detach
+ \ on If true attach, else detach the item
+
+ \sa setAutoDelete(), ~QwtPlotDict()
+*/
+void QwtPlotDict::attachItem( QwtPlotItem *item, bool on )
+{
+ if ( on )
+ d_data->itemList.insertItem( item );
+ else
+ d_data->itemList.removeItem( item );
+}
+
+/*!
+ Detach items from the dictionary
+
+ \param rtti In case of QwtPlotItem::Rtti_PlotItem detach all items
+ otherwise only those items of the type rtti.
+ \param autoDelete If true, delete all detached items
+*/
+void QwtPlotDict::detachItems( int rtti, bool autoDelete )
+{
+ PrivateData::ItemList list = d_data->itemList;
+ QwtPlotItemIterator it = list.begin();
+ while ( it != list.end() )
+ {
+ QwtPlotItem *item = *it;
+
+ ++it; // increment before removing item from the list
+
+ if ( rtti == QwtPlotItem::Rtti_PlotItem || item->rtti() == rtti )
+ {
+ item->attach( NULL );
+ if ( autoDelete )
+ delete item;
+ }
+ }
+}
+
+/*!
+ \brief A QwtPlotItemList of all attached plot items.
+
+ Use caution when iterating these lists, as removing/detaching an item will
+ invalidate the iterator. Instead you can place pointers to objects to be
+ removed in a removal list, and traverse that list later.
+
+ \return List of all attached plot items.
+*/
+const QwtPlotItemList &QwtPlotDict::itemList() const
+{
+ return d_data->itemList;
+}
+
+/*!
+ \return List of all attached plot items of a specific type.
+ \sa QwtPlotItem::rtti()
+*/
+QwtPlotItemList QwtPlotDict::itemList( int rtti ) const
+{
+ if ( rtti == QwtPlotItem::Rtti_PlotItem )
+ return d_data->itemList;
+
+ QwtPlotItemList items;
+
+ PrivateData::ItemList list = d_data->itemList;
+ for ( QwtPlotItemIterator it = list.begin(); it != list.end(); ++it )
+ {
+ QwtPlotItem *item = *it;
+ if ( item->rtti() == rtti )
+ items += item;
+ }
+
+ return items;
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_dict.h b/src/libpcp_qwt/src/qwt_plot_dict.h
new file mode 100644
index 0000000..0882d28
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_dict.h
@@ -0,0 +1,58 @@
+/* -*- 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
+ *****************************************************************************/
+
+/*! \file !*/
+#ifndef QWT_PLOT_DICT
+#define QWT_PLOT_DICT
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include <qlist.h>
+
+/// \var typedef QList< QwtPlotItem *> QwtPlotItemList
+/// \brief See QT 4.x assistant documentation for QList
+typedef QList<QwtPlotItem *> QwtPlotItemList;
+typedef QList<QwtPlotItem *>::ConstIterator QwtPlotItemIterator;
+
+/*!
+ \brief A dictionary for plot items
+
+ QwtPlotDict organizes plot items in increasing z-order.
+ If autoDelete() is enabled, all attached items will be deleted
+ in the destructor of the dictionary.
+ QwtPlotDict can be used to get access to all QwtPlotItem items - or all
+ items of a specific type - that are currently on the plot.
+
+ \sa QwtPlotItem::attach(), QwtPlotItem::detach(), QwtPlotItem::z()
+*/
+class QWT_EXPORT QwtPlotDict
+{
+public:
+ explicit QwtPlotDict();
+ virtual ~QwtPlotDict();
+
+ void setAutoDelete( bool );
+ bool autoDelete() const;
+
+ const QwtPlotItemList& itemList() const;
+ QwtPlotItemList itemList( int rtti ) const;
+
+ void detachItems( int rtti = QwtPlotItem::Rtti_PlotItem,
+ bool autoDelete = true );
+
+private:
+ friend class QwtPlotItem;
+
+ void attachItem( QwtPlotItem *, bool );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_directpainter.cpp b/src/libpcp_qwt/src/qwt_plot_directpainter.cpp
new file mode 100644
index 0000000..28682aa
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_directpainter.cpp
@@ -0,0 +1,313 @@
+/* -*- 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_plot_directpainter.h"
+#include "qwt_scale_map.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_plot_seriesitem.h"
+#include <qpainter.h>
+#include <qevent.h>
+#include <qapplication.h>
+#include <qpixmap.h>
+
+static inline void renderItem(
+ QPainter *painter, const QRect &canvasRect,
+ QwtPlotAbstractSeriesItem *seriesItem, int from, int to )
+{
+ // A minor performance improvement is possible
+ // with caching the maps. TODO ...
+
+ QwtPlot *plot = seriesItem->plot();
+ const QwtScaleMap xMap = plot->canvasMap( seriesItem->xAxis() );
+ const QwtScaleMap yMap = plot->canvasMap( seriesItem->yAxis() );
+
+ painter->setRenderHint( QPainter::Antialiasing,
+ seriesItem->testRenderHint( QwtPlotItem::RenderAntialiased ) );
+ seriesItem->drawSeries( painter, xMap, yMap, canvasRect, from, to );
+}
+
+class QwtPlotDirectPainter::PrivateData
+{
+public:
+ PrivateData():
+ attributes( 0 ),
+ hasClipping(false),
+ seriesItem( NULL )
+ {
+ }
+
+ QwtPlotDirectPainter::Attributes attributes;
+
+ bool hasClipping;
+ QRegion clipRegion;
+
+ QPainter painter;
+
+ QwtPlotAbstractSeriesItem *seriesItem;
+ int from;
+ int to;
+};
+
+//! Constructor
+QwtPlotDirectPainter::QwtPlotDirectPainter( QObject *parent ):
+ QObject( parent )
+{
+ d_data = new PrivateData;
+}
+
+//! Destructor
+QwtPlotDirectPainter::~QwtPlotDirectPainter()
+{
+ delete d_data;
+}
+
+/*!
+ Change an attribute
+
+ \param attribute Attribute to change
+ \param on On/Off
+
+ \sa Attribute, testAttribute()
+*/
+void QwtPlotDirectPainter::setAttribute( Attribute attribute, bool on )
+{
+ if ( bool( d_data->attributes & attribute ) != on )
+ {
+ if ( on )
+ d_data->attributes |= attribute;
+ else
+ d_data->attributes &= ~attribute;
+
+ if ( ( attribute == AtomicPainter ) && on )
+ reset();
+ }
+}
+
+/*!
+ Check if a attribute is set.
+
+ \param attribute Attribute to be tested
+ \sa Attribute, setAttribute()
+*/
+bool QwtPlotDirectPainter::testAttribute( Attribute attribute ) const
+{
+ return d_data->attributes & attribute;
+}
+
+/*!
+ En/Disables clipping
+
+ \param enable Enables clipping is true, disable it otherwise
+ \sa hasClipping(), clipRegion(), setClipRegion()
+*/
+void QwtPlotDirectPainter::setClipping( bool enable )
+{
+ d_data->hasClipping = enable;
+}
+
+/*!
+ \return true, when clipping is enabled
+ \sa setClipping(), clipRegion(), setClipRegion()
+*/
+bool QwtPlotDirectPainter::hasClipping() const
+{
+ return d_data->hasClipping;
+}
+
+/*!
+ \brief Assign a clip region and enable clipping
+
+ Depending on the environment setting a proper clip region might improve
+ the performance heavily. F.e. on Qt embedded only the clipped part of
+ the backing store will be copied to a ( maybe unaccelerated ) frame buffer
+ device.
+
+ \param region Clip region
+ \sa clipRegion(), hasClipping(), setClipping()
+*/
+void QwtPlotDirectPainter::setClipRegion( const QRegion &region )
+{
+ d_data->clipRegion = region;
+ d_data->hasClipping = true;
+}
+
+/*!
+ \return Currently set clip region.
+ \sa setClipRegion(), setClipping(), hasClipping()
+*/
+QRegion QwtPlotDirectPainter::clipRegion() const
+{
+ return d_data->clipRegion;
+}
+
+/*!
+ \brief Draw a set of points of a seriesItem.
+
+ When observing an measurement while it is running, new points have to be
+ added to an existing seriesItem. drawSeries can be used to display them avoiding
+ a complete redraw of the canvas.
+
+ Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
+ will result in faster painting, if the paint engine of the canvas widget
+ supports this feature.
+
+ \param seriesItem Item to be painted
+ \param from Index of the first point to be painted
+ \param to Index of the last point to be painted. If to < 0 the
+ series will be painted to its last point.
+*/
+void QwtPlotDirectPainter::drawSeries(
+ QwtPlotAbstractSeriesItem *seriesItem, int from, int to )
+{
+ if ( seriesItem == NULL || seriesItem->plot() == NULL )
+ return;
+
+ QwtPlotCanvas *canvas = seriesItem->plot()->canvas();
+ const QRect canvasRect = canvas->contentsRect();
+
+ const bool hasBackingStore =
+ canvas->testPaintAttribute( QwtPlotCanvas::BackingStore )
+ && canvas->backingStore() && !canvas->backingStore()->isNull();
+
+ if ( hasBackingStore )
+ {
+ QPainter painter( const_cast<QPixmap *>( canvas->backingStore() ) );
+
+ if ( d_data->hasClipping )
+ painter.setClipRegion( d_data->clipRegion );
+
+ renderItem( &painter, canvasRect, seriesItem, from, to );
+
+ if ( testAttribute( QwtPlotDirectPainter::FullRepaint ) )
+ {
+ canvas->repaint();
+ return;
+ }
+ }
+
+ bool immediatePaint = true;
+ if ( !canvas->testAttribute( Qt::WA_WState_InPaintEvent ) )
+ {
+#if QT_VERSION < 0x050000
+ if ( !canvas->testAttribute( Qt::WA_PaintOutsidePaintEvent ) )
+#endif
+ immediatePaint = false;
+ }
+
+ if ( immediatePaint )
+ {
+ if ( !d_data->painter.isActive() )
+ {
+ reset();
+
+ d_data->painter.begin( canvas );
+ canvas->installEventFilter( this );
+ }
+
+ if ( d_data->hasClipping )
+ {
+ d_data->painter.setClipRegion(
+ QRegion( canvasRect ) & d_data->clipRegion );
+ }
+ else
+ {
+ if ( !d_data->painter.hasClipping() )
+ d_data->painter.setClipRect( canvasRect );
+ }
+
+ renderItem( &d_data->painter, canvasRect, seriesItem, from, to );
+
+ if ( d_data->attributes & QwtPlotDirectPainter::AtomicPainter )
+ {
+ reset();
+ }
+ else
+ {
+ if ( d_data->hasClipping )
+ d_data->painter.setClipping( false );
+ }
+ }
+ else
+ {
+ reset();
+
+ d_data->seriesItem = seriesItem;
+ d_data->from = from;
+ d_data->to = to;
+
+ QRegion clipRegion = canvasRect;
+ if ( d_data->hasClipping )
+ clipRegion &= d_data->clipRegion;
+
+ canvas->installEventFilter( this );
+ canvas->repaint(clipRegion);
+ canvas->removeEventFilter( this );
+
+ d_data->seriesItem = NULL;
+ }
+}
+
+//! Close the internal QPainter
+void QwtPlotDirectPainter::reset()
+{
+ if ( d_data->painter.isActive() )
+ {
+ QWidget *w = ( QWidget * )d_data->painter.device();
+ if ( w )
+ w->removeEventFilter( this );
+
+ d_data->painter.end();
+ }
+}
+
+//! Event filter
+bool QwtPlotDirectPainter::eventFilter( QObject *, QEvent *event )
+{
+ if ( event->type() == QEvent::Paint )
+ {
+ reset();
+
+ if ( d_data->seriesItem )
+ {
+ const QPaintEvent *pe = static_cast< QPaintEvent *>( event );
+
+ QwtPlotCanvas *canvas = d_data->seriesItem->plot()->canvas();
+
+ QPainter painter( canvas );
+ painter.setClipRegion( pe->region() );
+
+ bool copyCache = testAttribute( CopyBackingStore )
+ && canvas->testPaintAttribute( QwtPlotCanvas::BackingStore );
+
+ if ( copyCache )
+ {
+ // is something valid in the cache ?
+ copyCache = ( canvas->backingStore() != NULL )
+ && !canvas->backingStore()->isNull();
+ }
+
+ if ( copyCache )
+ {
+ painter.drawPixmap(
+ canvas->contentsRect().topLeft(),
+ *canvas->backingStore() );
+ }
+ else
+ {
+ renderItem( &painter, canvas->contentsRect(),
+ d_data->seriesItem, d_data->from, d_data->to );
+ }
+
+ return true; // don't call QwtPlotCanvas::paintEvent()
+ }
+ }
+
+ return false;
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_directpainter.h b/src/libpcp_qwt/src/qwt_plot_directpainter.h
new file mode 100644
index 0000000..ca7dbf9
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_directpainter.h
@@ -0,0 +1,100 @@
+/* -*- 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_PLOT_DIRECT_PAINTER_H
+#define QWT_PLOT_DIRECT_PAINTER_H
+
+#include "qwt_global.h"
+#include <qobject.h>
+
+class QRegion;
+class QwtPlotAbstractSeriesItem;
+
+/*!
+ \brief Painter object trying to paint incrementally
+
+ Often applications want to display samples while they are
+ collected. When there are too many samples complete replots
+ will be expensive to be processed in a collection cycle.
+
+ QwtPlotDirectPainter offers an API to paint
+ subsets ( f.e all additions points ) without erasing/repainting
+ the plot canvas.
+
+ On certain environments it might be important to calculate a proper
+ clip region before painting. F.e. for Qt Embedded only the clipped part
+ of the backing store will be copied to a ( maybe unaccelerated )
+ frame buffer.
+
+ \warning Incremental painting will only help when no replot is triggered
+ by another operation ( like changing scales ) and nothing needs
+ to be erased.
+*/
+class QWT_EXPORT QwtPlotDirectPainter: public QObject
+{
+public:
+ /*!
+ \brief Paint attributes
+ \sa setAttribute(), testAttribute(), drawSeries()
+ */
+ enum Attribute
+ {
+ /*!
+ Initializing a QPainter is an expensive operation.
+ When AtomicPainter is set each call of drawSeries() opens/closes
+ a temporary QPainter. Otherwise QwtPlotDirectPainter tries to
+ use the same QPainter as long as possible.
+ */
+ AtomicPainter = 0x01,
+
+ /*!
+ When FullRepaint is set the plot canvas is explicitely repainted
+ after the samples have been rendered.
+ */
+ FullRepaint = 0x02,
+
+ /*!
+ When QwtPlotCanvas::BackingStore is enabled the painter
+ has to paint to the backing store and the widget. In certain
+ situations/environments it might be faster to paint to
+ the backing store only and then copy the backingstore to the canvas.
+ This flag can also be useful for settings, where Qt fills the
+ the clip region with the widget background.
+ */
+ CopyBackingStore = 0x04
+ };
+
+ //! Paint attributes
+ typedef QFlags<Attribute> Attributes;
+
+ QwtPlotDirectPainter( QObject *parent = NULL );
+ virtual ~QwtPlotDirectPainter();
+
+ void setAttribute( Attribute, bool on );
+ bool testAttribute( Attribute ) const;
+
+ void setClipping( bool );
+ bool hasClipping() const;
+
+ void setClipRegion( const QRegion & );
+ QRegion clipRegion() const;
+
+ void drawSeries( QwtPlotAbstractSeriesItem *, int from, int to );
+ void reset();
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotDirectPainter::Attributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_grid.cpp b/src/libpcp_qwt/src/qwt_plot_grid.cpp
new file mode 100644
index 0000000..8e25aeb
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_grid.cpp
@@ -0,0 +1,367 @@
+/* -*- 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_plot_grid.h"
+#include "qwt_painter.h"
+#include "qwt_text.h"
+#include "qwt_scale_map.h"
+#include "qwt_scale_div.h"
+#include "qwt_math.h"
+#include <qpainter.h>
+#include <qpen.h>
+
+class QwtPlotGrid::PrivateData
+{
+public:
+ PrivateData():
+ xEnabled( true ),
+ yEnabled( true ),
+ xMinEnabled( false ),
+ yMinEnabled( false )
+ {
+ }
+
+ bool xEnabled;
+ bool yEnabled;
+ bool xMinEnabled;
+ bool yMinEnabled;
+
+ QwtScaleDiv xScaleDiv;
+ QwtScaleDiv yScaleDiv;
+
+ QPen majPen;
+ QPen minPen;
+};
+
+//! Enables major grid, disables minor grid
+QwtPlotGrid::QwtPlotGrid():
+ QwtPlotItem( QwtText( "Grid" ) )
+{
+ d_data = new PrivateData;
+ setZ( 10.0 );
+}
+
+//! Destructor
+QwtPlotGrid::~QwtPlotGrid()
+{
+ delete d_data;
+}
+
+//! \return QwtPlotItem::Rtti_PlotGrid
+int QwtPlotGrid::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotGrid;
+}
+
+/*!
+ \brief Enable or disable vertical gridlines
+ \param tf Enable (true) or disable
+
+ \sa Minor gridlines can be enabled or disabled with
+ enableXMin()
+*/
+void QwtPlotGrid::enableX( bool tf )
+{
+ if ( d_data->xEnabled != tf )
+ {
+ d_data->xEnabled = tf;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Enable or disable horizontal gridlines
+ \param tf Enable (true) or disable
+ \sa Minor gridlines can be enabled or disabled with enableYMin()
+*/
+void QwtPlotGrid::enableY( bool tf )
+{
+ if ( d_data->yEnabled != tf )
+ {
+ d_data->yEnabled = tf;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Enable or disable minor vertical gridlines.
+ \param tf Enable (true) or disable
+ \sa enableX()
+*/
+void QwtPlotGrid::enableXMin( bool tf )
+{
+ if ( d_data->xMinEnabled != tf )
+ {
+ d_data->xMinEnabled = tf;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Enable or disable minor horizontal gridlines
+ \param tf Enable (true) or disable
+ \sa enableY()
+*/
+void QwtPlotGrid::enableYMin( bool tf )
+{
+ if ( d_data->yMinEnabled != tf )
+ {
+ d_data->yMinEnabled = tf;
+ itemChanged();
+ }
+}
+
+/*!
+ Assign an x axis scale division
+
+ \param scaleDiv Scale division
+*/
+void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv )
+{
+ if ( d_data->xScaleDiv != scaleDiv )
+ {
+ d_data->xScaleDiv = scaleDiv;
+ itemChanged();
+ }
+}
+
+/*!
+ Assign a y axis division
+
+ \param scaleDiv Scale division
+*/
+void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv )
+{
+ if ( d_data->yScaleDiv != scaleDiv )
+ {
+ d_data->yScaleDiv = scaleDiv;
+ itemChanged();
+ }
+}
+
+/*!
+ Assign a pen for both major and minor gridlines
+
+ \param pen Pen
+ \sa setMajPen(), setMinPen()
+*/
+void QwtPlotGrid::setPen( const QPen &pen )
+{
+ if ( d_data->majPen != pen || d_data->minPen != pen )
+ {
+ d_data->majPen = pen;
+ d_data->minPen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ Assign a pen for the major gridlines
+
+ \param pen Pen
+ \sa majPen(), setMinPen(), setPen()
+*/
+void QwtPlotGrid::setMajPen( const QPen &pen )
+{
+ if ( d_data->majPen != pen )
+ {
+ d_data->majPen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ Assign a pen for the minor gridlines
+
+ \param pen Pen
+ \sa minPen(), setMajPen(), setPen()
+*/
+void QwtPlotGrid::setMinPen( const QPen &pen )
+{
+ if ( d_data->minPen != pen )
+ {
+ d_data->minPen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Draw the grid
+
+ The grid is drawn into the bounding rectangle such that
+ gridlines begin and end at the rectangle's borders. The X and Y
+ maps are used to map the scale divisions into the drawing region
+ screen.
+ \param painter Painter
+ \param xMap X axis map
+ \param yMap Y axis
+ \param canvasRect Contents rect of the plot canvas
+*/
+void QwtPlotGrid::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ // draw minor gridlines
+ QPen minPen = d_data->minPen;
+ minPen.setCapStyle( Qt::FlatCap );
+
+ painter->setPen( minPen );
+
+ if ( d_data->xEnabled && d_data->xMinEnabled )
+ {
+ drawLines( painter, canvasRect, Qt::Vertical, xMap,
+ d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
+ drawLines( painter, canvasRect, Qt::Vertical, xMap,
+ d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
+ }
+
+ if ( d_data->yEnabled && d_data->yMinEnabled )
+ {
+ drawLines( painter, canvasRect, Qt::Horizontal, yMap,
+ d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
+ drawLines( painter, canvasRect, Qt::Horizontal, yMap,
+ d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
+ }
+
+ // draw major gridlines
+ QPen majPen = d_data->majPen;
+ majPen.setCapStyle( Qt::FlatCap );
+
+ painter->setPen( majPen );
+
+ if ( d_data->xEnabled )
+ {
+ drawLines( painter, canvasRect, Qt::Vertical, xMap,
+ d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
+ }
+
+ if ( d_data->yEnabled )
+ {
+ drawLines( painter, canvasRect, Qt::Horizontal, yMap,
+ d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
+ }
+}
+
+void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect,
+ Qt::Orientation orientation, const QwtScaleMap &scaleMap,
+ const QList<double> &values ) const
+{
+ const double x1 = canvasRect.left();
+ const double x2 = canvasRect.right() - 1.0;
+ const double y1 = canvasRect.top();
+ const double y2 = canvasRect.bottom() - 1.0;
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ for ( int i = 0; i < values.count(); i++ )
+ {
+ double value = scaleMap.transform( values[i] );
+ if ( doAlign )
+ value = qRound( value );
+
+ if ( orientation == Qt::Horizontal )
+ {
+ if ( qwtFuzzyGreaterOrEqual( value, y1 ) &&
+ qwtFuzzyLessOrEqual( value, y2 ) )
+ {
+ QwtPainter::drawLine( painter, x1, value, x2, value );
+ }
+ }
+ else
+ {
+ if ( qwtFuzzyGreaterOrEqual( value, x1 ) &&
+ qwtFuzzyLessOrEqual( value, x2 ) )
+ {
+ QwtPainter::drawLine( painter, value, y1, value, y2 );
+ }
+ }
+ }
+}
+
+/*!
+ \return the pen for the major gridlines
+ \sa setMajPen(), setMinPen(), setPen()
+*/
+const QPen &QwtPlotGrid::majPen() const
+{
+ return d_data->majPen;
+}
+
+/*!
+ \return the pen for the minor gridlines
+ \sa setMinPen(), setMajPen(), setPen()
+*/
+const QPen &QwtPlotGrid::minPen() const
+{
+ return d_data->minPen;
+}
+
+/*!
+ \return true if vertical gridlines are enabled
+ \sa enableX()
+*/
+bool QwtPlotGrid::xEnabled() const
+{
+ return d_data->xEnabled;
+}
+
+/*!
+ \return true if minor vertical gridlines are enabled
+ \sa enableXMin()
+*/
+bool QwtPlotGrid::xMinEnabled() const
+{
+ return d_data->xMinEnabled;
+}
+
+/*!
+ \return true if horizontal gridlines are enabled
+ \sa enableY()
+*/
+bool QwtPlotGrid::yEnabled() const
+{
+ return d_data->yEnabled;
+}
+
+/*!
+ \return true if minor horizontal gridlines are enabled
+ \sa enableYMin()
+*/
+bool QwtPlotGrid::yMinEnabled() const
+{
+ return d_data->yMinEnabled;
+}
+
+
+/*! \return the scale division of the x axis */
+const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const
+{
+ return d_data->xScaleDiv;
+}
+
+/*! \return the scale division of the y axis */
+const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const
+{
+ return d_data->yScaleDiv;
+}
+
+/*!
+ Update the grid to changes of the axes scale division
+
+ \param xScaleDiv Scale division of the x-axis
+ \param yScaleDiv Scale division of the y-axis
+
+ \sa QwtPlot::updateAxes()
+*/
+void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
+ const QwtScaleDiv& yScaleDiv )
+{
+ setXDiv( xScaleDiv );
+ setYDiv( yScaleDiv );
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_grid.h b/src/libpcp_qwt/src/qwt_plot_grid.h
new file mode 100644
index 0000000..361ec81
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_grid.h
@@ -0,0 +1,84 @@
+/* -*- 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_PLOT_GRID_H
+#define QWT_PLOT_GRID_H
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include "qwt_scale_div.h"
+
+class QPainter;
+class QPen;
+class QwtScaleMap;
+class QwtScaleDiv;
+
+/*!
+ \brief A class which draws a coordinate grid
+
+ The QwtPlotGrid class can be used to draw a coordinate grid.
+ A coordinate grid consists of major and minor vertical
+ and horizontal gridlines. The locations of the gridlines
+ are determined by the X and Y scale divisions which can
+ be assigned with setXDiv() and setYDiv().
+ The draw() member draws the grid within a bounding
+ rectangle.
+*/
+
+class QWT_EXPORT QwtPlotGrid: public QwtPlotItem
+{
+public:
+ explicit QwtPlotGrid();
+ virtual ~QwtPlotGrid();
+
+ virtual int rtti() const;
+
+ void enableX( bool tf );
+ bool xEnabled() const;
+
+ void enableY( bool tf );
+ bool yEnabled() const;
+
+ void enableXMin( bool tf );
+ bool xMinEnabled() const;
+
+ void enableYMin( bool tf );
+ bool yMinEnabled() const;
+
+ void setXDiv( const QwtScaleDiv &sx );
+ const QwtScaleDiv &xScaleDiv() const;
+
+ void setYDiv( const QwtScaleDiv &sy );
+ const QwtScaleDiv &yScaleDiv() const;
+
+ void setPen( const QPen &p );
+
+ void setMajPen( const QPen &p );
+ const QPen& majPen() const;
+
+ void setMinPen( const QPen &p );
+ const QPen& minPen() const;
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &rect ) const;
+
+ virtual void updateScaleDiv(
+ const QwtScaleDiv &xMap, const QwtScaleDiv &yMap );
+
+private:
+ void drawLines( QPainter *painter, const QRectF &,
+ Qt::Orientation orientation, const QwtScaleMap &,
+ const QList<double> & ) const;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_histogram.cpp b/src/libpcp_qwt/src/qwt_plot_histogram.cpp
new file mode 100644
index 0000000..53d0551
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_histogram.cpp
@@ -0,0 +1,651 @@
+/* -*- 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_plot_histogram.h"
+#include "qwt_plot.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_painter.h"
+#include "qwt_column_symbol.h"
+#include "qwt_scale_map.h"
+#include <qstring.h>
+#include <qpainter.h>
+
+static inline bool isCombinable( const QwtInterval &d1,
+ const QwtInterval &d2 )
+{
+ if ( d1.isValid() && d2.isValid() )
+ {
+ if ( d1.maxValue() == d2.minValue() )
+ {
+ if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum
+ && d2.borderFlags() & QwtInterval::ExcludeMinimum ) )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+class QwtPlotHistogram::PrivateData
+{
+public:
+ PrivateData():
+ baseline( 0.0 ),
+ style( Columns ),
+ symbol( NULL )
+ {
+ }
+
+ ~PrivateData()
+ {
+ delete symbol;
+ }
+
+ double baseline;
+
+ QPen pen;
+ QBrush brush;
+ QwtPlotHistogram::HistogramStyle style;
+ const QwtColumnSymbol *symbol;
+};
+
+/*!
+ Constructor
+ \param title Title of the histogram.
+*/
+
+QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ):
+ QwtPlotSeriesItem<QwtIntervalSample>( title )
+{
+ init();
+}
+
+/*!
+ Constructor
+ \param title Title of the histogram.
+*/
+QwtPlotHistogram::QwtPlotHistogram( const QString &title ):
+ QwtPlotSeriesItem<QwtIntervalSample>( title )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotHistogram::~QwtPlotHistogram()
+{
+ delete d_data;
+}
+
+//! Initialize data members
+void QwtPlotHistogram::init()
+{
+ d_data = new PrivateData();
+ d_series = new QwtIntervalSeriesData();
+
+ setItemAttribute( QwtPlotItem::AutoScale, true );
+ setItemAttribute( QwtPlotItem::Legend, true );
+
+ setZ( 20.0 );
+}
+
+/*!
+ Set the histogram's drawing style
+
+ \param style Histogram style
+ \sa HistogramStyle, style()
+*/
+void QwtPlotHistogram::setStyle( HistogramStyle style )
+{
+ if ( style != d_data->style )
+ {
+ d_data->style = style;
+ itemChanged();
+ }
+}
+
+/*!
+ Return the current style
+ \sa HistogramStyle, setStyle()
+*/
+QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const
+{
+ return d_data->style;
+}
+
+/*!
+ Assign a pen, that is used in a style() depending way.
+
+ \param pen New pen
+ \sa pen(), brush()
+*/
+void QwtPlotHistogram::setPen( const QPen &pen )
+{
+ if ( pen != d_data->pen )
+ {
+ d_data->pen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Pen used in a style() depending way.
+ \sa setPen(), brush()
+*/
+const QPen &QwtPlotHistogram::pen() const
+{
+ return d_data->pen;
+}
+
+/*!
+ Assign a brush, that is used in a style() depending way.
+
+ \param brush New brush
+ \sa pen(), brush()
+*/
+void QwtPlotHistogram::setBrush( const QBrush &brush )
+{
+ if ( brush != d_data->brush )
+ {
+ d_data->brush = brush;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Brush used in a style() depending way.
+ \sa setPen(), brush()
+*/
+const QBrush &QwtPlotHistogram::brush() const
+{
+ return d_data->brush;
+}
+
+/*!
+ \brief Assign a symbol
+
+ In Column style an optional symbol can be assigned, that is responsible
+ for displaying the rectangle that is defined by the interval and
+ the distance between baseline() and value. When no symbol has been
+ defined the area is displayed as plain rectangle using pen() and brush().
+
+ \sa style(), symbol(), drawColumn(), pen(), brush()
+
+ \note In applications, where different intervals need to be displayed
+ in a different way ( f.e different colors or even using differnt symbols)
+ it is recommended to overload drawColumn().
+*/
+void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol )
+{
+ if ( symbol != d_data->symbol )
+ {
+ delete d_data->symbol;
+ d_data->symbol = symbol;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Current symbol or NULL, when no symbol has been assigned
+ \sa setSymbol()
+*/
+const QwtColumnSymbol *QwtPlotHistogram::symbol() const
+{
+ return d_data->symbol;
+}
+
+/*!
+ \brief Set the value of the baseline
+
+ Each column representing an QwtIntervalSample is defined by its
+ interval and the interval between baseline and the value of the sample.
+
+ The default value of the baseline is 0.0.
+
+ \param value Value of the baseline
+ \sa baseline()
+*/
+void QwtPlotHistogram::setBaseline( double value )
+{
+ if ( d_data->baseline != value )
+ {
+ d_data->baseline = value;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Value of the baseline
+ \sa setBaseline()
+*/
+double QwtPlotHistogram::baseline() const
+{
+ return d_data->baseline;
+}
+
+/*!
+ \return Bounding rectangle of all samples.
+ For an empty series the rectangle is invalid.
+*/
+QRectF QwtPlotHistogram::boundingRect() const
+{
+ QRectF rect = d_series->boundingRect();
+ if ( !rect.isValid() )
+ return rect;
+
+ if ( orientation() == Qt::Horizontal )
+ {
+ rect = QRectF( rect.y(), rect.x(),
+ rect.height(), rect.width() );
+
+ if ( rect.left() > d_data->baseline )
+ rect.setLeft( d_data->baseline );
+ else if ( rect.right() < d_data->baseline )
+ rect.setRight( d_data->baseline );
+ }
+ else
+ {
+ if ( rect.bottom() < d_data->baseline )
+ rect.setBottom( d_data->baseline );
+ else if ( rect.top() > d_data->baseline )
+ rect.setTop( d_data->baseline );
+ }
+
+ return rect;
+}
+
+//! \return QwtPlotItem::Rtti_PlotHistogram
+int QwtPlotHistogram::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotHistogram;
+}
+
+/*!
+ Initialize data with an array of samples.
+ \param samples Vector of points
+*/
+void QwtPlotHistogram::setSamples(
+ const QVector<QwtIntervalSample> &samples )
+{
+ delete d_series;
+ d_series = new QwtIntervalSeriesData( samples );
+ itemChanged();
+}
+
+/*!
+ Draw a subset of the histogram samples
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ series will be painted to its last sample.
+
+ \sa drawOutline(), drawLines(), drawColumns
+*/
+void QwtPlotHistogram::drawSeries( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &, int from, int to ) const
+{
+ if ( !painter || dataSize() <= 0 )
+ return;
+
+ if ( to < 0 )
+ to = dataSize() - 1;
+
+ switch ( d_data->style )
+ {
+ case Outline:
+ drawOutline( painter, xMap, yMap, from, to );
+ break;
+ case Lines:
+ drawLines( painter, xMap, yMap, from, to );
+ break;
+ case Columns:
+ drawColumns( painter, xMap, yMap, from, to );
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Draw a histogram in Outline style()
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ histogram will be painted to its last point.
+
+ \sa setStyle(), style()
+ \warning The outline style requires, that the intervals are in increasing
+ order and not overlapping.
+*/
+void QwtPlotHistogram::drawOutline( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ double v0 = ( orientation() == Qt::Horizontal ) ?
+ xMap.transform( baseline() ) : yMap.transform( baseline() );
+ if ( doAlign )
+ v0 = qRound( v0 );
+
+ QwtIntervalSample previous;
+
+ QPolygonF polygon;
+ for ( int i = from; i <= to; i++ )
+ {
+ const QwtIntervalSample sample = d_series->sample( i );
+
+ if ( !sample.interval.isValid() )
+ {
+ flushPolygon( painter, v0, polygon );
+ previous = sample;
+ continue;
+ }
+
+ if ( previous.interval.isValid() )
+ {
+ if ( !isCombinable( previous.interval, sample.interval ) )
+ flushPolygon( painter, v0, polygon );
+ }
+
+ if ( orientation() == Qt::Vertical )
+ {
+ double x1 = xMap.transform( sample.interval.minValue() );
+ double x2 = xMap.transform( sample.interval.maxValue() );
+ double y = yMap.transform( sample.value );
+ if ( doAlign )
+ {
+ x1 = qRound( x1 );
+ x2 = qRound( x2 );
+ y = qRound( y );
+ }
+
+ if ( polygon.size() == 0 )
+ polygon += QPointF( x1, v0 );
+
+ polygon += QPointF( x1, y );
+ polygon += QPointF( x2, y );
+ }
+ else
+ {
+ double y1 = yMap.transform( sample.interval.minValue() );
+ double y2 = yMap.transform( sample.interval.maxValue() );
+ double x = xMap.transform( sample.value );
+ if ( doAlign )
+ {
+ y1 = qRound( y1 );
+ y2 = qRound( y2 );
+ x = qRound( x );
+ }
+
+ if ( polygon.size() == 0 )
+ polygon += QPointF( v0, y1 );
+
+ polygon += QPointF( x, y1 );
+ polygon += QPointF( x, y2 );
+ }
+ previous = sample;
+ }
+
+ flushPolygon( painter, v0, polygon );
+}
+
+/*!
+ Draw a histogram in Columns style()
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ histogram will be painted to its last point.
+
+ \sa setStyle(), style(), setSymbol(), drawColumn()
+*/
+void QwtPlotHistogram::drawColumns( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const
+{
+ painter->setPen( d_data->pen );
+ painter->setBrush( d_data->brush );
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QwtIntervalSample sample = d_series->sample( i );
+ if ( !sample.interval.isNull() )
+ {
+ const QwtColumnRect rect = columnRect( sample, xMap, yMap );
+ drawColumn( painter, rect, sample );
+ }
+ }
+}
+
+/*!
+ Draw a histogram in Lines style()
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ histogram will be painted to its last point.
+
+ \sa setStyle(), style(), setPen()
+*/
+void QwtPlotHistogram::drawLines( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ painter->setPen( d_data->pen );
+ painter->setBrush( Qt::NoBrush );
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QwtIntervalSample sample = d_series->sample( i );
+ if ( !sample.interval.isNull() )
+ {
+ const QwtColumnRect rect = columnRect( sample, xMap, yMap );
+
+ QRectF r = rect.toRect();
+ if ( doAlign )
+ {
+ r.setLeft( qRound( r.left() ) );
+ r.setRight( qRound( r.right() ) );
+ r.setTop( qRound( r.top() ) );
+ r.setBottom( qRound( r.bottom() ) );
+ }
+
+ switch ( rect.direction )
+ {
+ case QwtColumnRect::LeftToRight:
+ {
+ QwtPainter::drawLine( painter,
+ r.topRight(), r.bottomRight() );
+ break;
+ }
+ case QwtColumnRect::RightToLeft:
+ {
+ QwtPainter::drawLine( painter,
+ r.topLeft(), r.bottomLeft() );
+ break;
+ }
+ case QwtColumnRect::TopToBottom:
+ {
+ QwtPainter::drawLine( painter,
+ r.bottomRight(), r.bottomLeft() );
+ break;
+ }
+ case QwtColumnRect::BottomToTop:
+ {
+ QwtPainter::drawLine( painter,
+ r.topRight(), r.topLeft() );
+ break;
+ }
+ }
+ }
+ }
+}
+
+//! Internal, used by the Outline style.
+void QwtPlotHistogram::flushPolygon( QPainter *painter,
+ double baseLine, QPolygonF &polygon ) const
+{
+ if ( polygon.size() == 0 )
+ return;
+
+ if ( orientation() == Qt::Horizontal )
+ polygon += QPointF( baseLine, polygon.last().y() );
+ else
+ polygon += QPointF( polygon.last().x(), baseLine );
+
+ if ( d_data->brush.style() != Qt::NoBrush )
+ {
+ painter->setPen( Qt::NoPen );
+ painter->setBrush( d_data->brush );
+
+ if ( orientation() == Qt::Horizontal )
+ {
+ polygon += QPointF( polygon.last().x(), baseLine );
+ polygon += QPointF( polygon.first().x(), baseLine );
+ }
+ else
+ {
+ polygon += QPointF( baseLine, polygon.last().y() );
+ polygon += QPointF( baseLine, polygon.first().y() );
+ }
+ QwtPainter::drawPolygon( painter, polygon );
+ int resize = polygon.size();
+ if ( resize > 1 )
+ resize -= 2;
+ polygon.resize( resize );
+ }
+ if ( d_data->pen.style() != Qt::NoPen )
+ {
+ painter->setBrush( Qt::NoBrush );
+ painter->setPen( d_data->pen );
+ QwtPainter::drawPolyline( painter, polygon );
+ }
+ polygon.clear();
+}
+
+/*!
+ Calculate the area that is covered by a sample
+
+ \param sample Sample
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+
+ \return Rectangle, that is covered by a sample
+*/
+QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const
+{
+ QwtColumnRect rect;
+
+ const QwtInterval &iv = sample.interval;
+ if ( !iv.isValid() )
+ return rect;
+
+ if ( orientation() == Qt::Horizontal )
+ {
+ const double x0 = xMap.transform( baseline() );
+ const double x = xMap.transform( sample.value );
+ const double y1 = yMap.transform( iv.minValue() );
+ const double y2 = yMap.transform( iv.maxValue() );
+
+ rect.hInterval.setInterval( x0, x );
+ rect.vInterval.setInterval( y1, y2, iv.borderFlags() );
+ rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft :
+ QwtColumnRect::LeftToRight;
+ }
+ else
+ {
+ const double x1 = xMap.transform( iv.minValue() );
+ const double x2 = xMap.transform( iv.maxValue() );
+ const double y0 = yMap.transform( baseline() );
+ const double y = yMap.transform( sample.value );
+
+ rect.hInterval.setInterval( x1, x2, iv.borderFlags() );
+ rect.vInterval.setInterval( y0, y );
+ rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop :
+ QwtColumnRect::TopToBottom;
+ }
+
+ return rect;
+}
+
+/*!
+ Draw a column for a sample in Columns style().
+
+ When a symbol() has been set the symbol is used otherwise the
+ column is displayed as plain rectangle using pen() and brush().
+
+ \param painter Painter
+ \param rect Rectangle where to paint the column in paint device coordinates
+ \param sample Sample to be displayed
+
+ \note In applications, where different intervals need to be displayed
+ in a different way ( f.e different colors or even using differnt symbols)
+ it is recommended to overload drawColumn().
+*/
+void QwtPlotHistogram::drawColumn( QPainter *painter,
+ const QwtColumnRect &rect, const QwtIntervalSample &sample ) const
+{
+ Q_UNUSED( sample );
+
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) )
+ {
+ d_data->symbol->draw( painter, rect );
+ }
+ else
+ {
+ 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() ) );
+ }
+
+ QwtPainter::drawRect( painter, r );
+ }
+}
+
+/*!
+ Draw a plain rectangle without pen using the brush() as identifier
+
+ \param painter Painter
+ \param rect Bounding rectangle for the identifier
+*/
+void QwtPlotHistogram::drawLegendIdentifier(
+ QPainter *painter, const QRectF &rect ) const
+{
+ const double dim = qMin( rect.width(), rect.height() );
+
+ QSizeF size( dim, dim );
+
+ QRectF r( 0, 0, size.width(), size.height() );
+ r.moveCenter( rect.center() );
+
+ painter->fillRect( r, d_data->brush );
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_histogram.h b/src/libpcp_qwt/src/qwt_plot_histogram.h
new file mode 100644
index 0000000..3e40c45
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_histogram.h
@@ -0,0 +1,134 @@
+/* -*- 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_PLOT_HISTOGRAM_H
+#define QWT_PLOT_HISTOGRAM_H
+
+#include "qwt_global.h"
+#include "qwt_plot_seriesitem.h"
+#include "qwt_column_symbol.h"
+#include <qcolor.h>
+#include <qvector.h>
+
+class QwtIntervalData;
+class QString;
+class QPolygonF;
+
+/*!
+ \brief QwtPlotHistogram represents a series of samples, where an interval
+ is associated with a value ( \f$y = f([x1,x2])\f$ ).
+
+ The representation depends on the style() and an optional symbol()
+ that is displayed for each interval.
+
+ \note The term "histogram" is used in a different way in the areas of
+ digital image processing and statistics. Wikipedia introduces the
+ terms "image histogram" and "color histogram" to avoid confusions.
+ While "image histograms" can be displayed by a QwtPlotCurve there
+ is no applicable plot item for a "color histogram" yet.
+*/
+
+class QWT_EXPORT QwtPlotHistogram: public QwtPlotSeriesItem<QwtIntervalSample>
+{
+public:
+ /*!
+ Histogram styles.
+ The default style is QwtPlotHistogram::Columns.
+
+ \sa setStyle(), style(), setSymbol(), symbol(), setBaseline()
+ */
+ enum HistogramStyle
+ {
+ /*!
+ Draw an outline around the area, that is build by all intervals
+ using the pen() and fill it with the brush(). The outline style
+ requires, that the intervals are in increasing order and
+ not overlapping.
+ */
+ Outline,
+
+ /*!
+ Draw a column for each interval. When a symbol() has been set
+ the symbol is used otherwise the column is displayed as
+ plain rectangle using pen() and brush().
+ */
+ Columns,
+
+ /*!
+ Draw a simple line using the pen() for each interval.
+ */
+ Lines,
+
+ /*!
+ Styles >= UserStyle are reserved for derived
+ classes that overload drawSeries() with
+ additional application specific ways to display a histogram.
+ */
+ UserStyle = 100
+ };
+
+ explicit QwtPlotHistogram( const QString &title = QString::null );
+ explicit QwtPlotHistogram( const QwtText &title );
+ virtual ~QwtPlotHistogram();
+
+ virtual int rtti() const;
+
+ void setPen( const QPen & );
+ const QPen &pen() const;
+
+ void setBrush( const QBrush & );
+ const QBrush &brush() const;
+
+ void setSamples( const QVector<QwtIntervalSample> & );
+
+ void setBaseline( double reference );
+ double baseline() const;
+
+ void setStyle( HistogramStyle style );
+ HistogramStyle style() const;
+
+ void setSymbol( const QwtColumnSymbol * );
+ const QwtColumnSymbol *symbol() const;
+
+ virtual void drawSeries( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual QRectF boundingRect() const;
+
+ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const;
+
+protected:
+ virtual QwtColumnRect columnRect( const QwtIntervalSample &,
+ const QwtScaleMap &, const QwtScaleMap & ) const;
+
+ virtual void drawColumn( QPainter *, const QwtColumnRect &,
+ const QwtIntervalSample & ) const;
+
+ void drawColumns( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const;
+
+ void drawOutline( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const;
+
+ void drawLines( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ int from, int to ) const;
+
+private:
+ void init();
+ void flushPolygon( QPainter *, double baseLine, QPolygonF & ) const;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_intervalcurve.cpp b/src/libpcp_qwt/src/qwt_plot_intervalcurve.cpp
new file mode 100644
index 0000000..1edf0f1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_intervalcurve.cpp
@@ -0,0 +1,548 @@
+/* -*- 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_plot_intervalcurve.h"
+#include "qwt_interval_symbol.h"
+#include "qwt_scale_map.h"
+#include "qwt_clipper.h"
+#include "qwt_painter.h"
+
+#include <qpainter.h>
+
+static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample,
+ double xMin, double xMax, double yMin, double yMax )
+{
+ const double y = sample.value;
+ const double x1 = sample.interval.minValue();
+ const double x2 = sample.interval.maxValue();
+
+ const bool isOffScreen = ( y < yMin ) || ( y > yMax )
+ || ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax );
+
+ return !isOffScreen;
+}
+
+static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample,
+ double xMin, double xMax, double yMin, double yMax )
+{
+ const double x = sample.value;
+ const double y1 = sample.interval.minValue();
+ const double y2 = sample.interval.maxValue();
+
+ const bool isOffScreen = ( x < xMin ) || ( x > xMax )
+ || ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax );
+
+ return !isOffScreen;
+}
+
+class QwtPlotIntervalCurve::PrivateData
+{
+public:
+ PrivateData():
+ style( QwtPlotIntervalCurve::Tube ),
+ symbol( NULL ),
+ pen( Qt::black ),
+ brush( Qt::white )
+ {
+ paintAttributes = QwtPlotIntervalCurve::ClipPolygons;
+ paintAttributes |= QwtPlotIntervalCurve::ClipSymbol;
+
+ pen.setCapStyle( Qt::FlatCap );
+ }
+
+ ~PrivateData()
+ {
+ delete symbol;
+ }
+
+ QwtPlotIntervalCurve::CurveStyle style;
+ const QwtIntervalSymbol *symbol;
+
+ QPen pen;
+ QBrush brush;
+
+ QwtPlotIntervalCurve::PaintAttributes paintAttributes;
+};
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ):
+ QwtPlotSeriesItem<QwtIntervalSample>( title )
+{
+ init();
+}
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ):
+ QwtPlotSeriesItem<QwtIntervalSample>( QwtText( title ) )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotIntervalCurve::~QwtPlotIntervalCurve()
+{
+ delete d_data;
+}
+
+//! Initialize internal members
+void QwtPlotIntervalCurve::init()
+{
+ setItemAttribute( QwtPlotItem::Legend, true );
+ setItemAttribute( QwtPlotItem::AutoScale, true );
+
+ d_data = new PrivateData;
+ d_series = new QwtIntervalSeriesData();
+
+ setZ( 19.0 );
+}
+
+//! \return QwtPlotItem::Rtti_PlotIntervalCurve
+int QwtPlotIntervalCurve::rtti() const
+{
+ return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve;
+}
+
+/*!
+ Specify an attribute how to draw the curve
+
+ \param attribute Paint attribute
+ \param on On/Off
+ \sa testPaintAttribute()
+*/
+void QwtPlotIntervalCurve::setPaintAttribute(
+ PaintAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+}
+
+/*!
+ \brief Return the current paint attributes
+ \sa PaintAttribute, setPaintAttribute()
+*/
+bool QwtPlotIntervalCurve::testPaintAttribute(
+ PaintAttribute attribute ) const
+{
+ return ( d_data->paintAttributes & attribute );
+}
+
+/*!
+ Initialize data with an array of samples.
+ \param samples Vector of samples
+*/
+void QwtPlotIntervalCurve::setSamples(
+ const QVector<QwtIntervalSample> &samples )
+{
+ delete d_series;
+ d_series = new QwtIntervalSeriesData( samples );
+ itemChanged();
+}
+
+/*!
+ Set the curve's drawing style
+
+ \param style Curve style
+ \sa CurveStyle, style()
+*/
+void QwtPlotIntervalCurve::setStyle( CurveStyle style )
+{
+ if ( style != d_data->style )
+ {
+ d_data->style = style;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Return the current style
+ \sa setStyle()
+*/
+QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const
+{
+ return d_data->style;
+}
+
+/*!
+ Assign a symbol.
+
+ \param symbol Symbol
+ \sa symbol()
+*/
+void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol )
+{
+ if ( symbol != d_data->symbol )
+ {
+ delete d_data->symbol;
+ d_data->symbol = symbol;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Current symbol or NULL, when no symbol has been assigned
+ \sa setSymbol()
+*/
+const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const
+{
+ return d_data->symbol;
+}
+
+/*!
+ \brief Assign a pen
+ \param pen New pen
+ \sa pen(), brush()
+*/
+void QwtPlotIntervalCurve::setPen( const QPen &pen )
+{
+ if ( pen != d_data->pen )
+ {
+ d_data->pen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Return the pen used to draw the lines
+ \sa setPen(), brush()
+*/
+const QPen& QwtPlotIntervalCurve::pen() const
+{
+ return d_data->pen;
+}
+
+/*!
+ Assign a brush.
+
+ The brush is used to fill the area in Tube style().
+
+ \param brush Brush
+ \sa brush(), pen(), setStyle(), CurveStyle
+*/
+void QwtPlotIntervalCurve::setBrush( const QBrush &brush )
+{
+ if ( brush != d_data->brush )
+ {
+ d_data->brush = brush;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Brush used to fill the area in Tube style()
+ \sa setBrush(), setStyle(), CurveStyle
+*/
+const QBrush& QwtPlotIntervalCurve::brush() const
+{
+ return d_data->brush;
+}
+
+/*!
+ \return Bounding rectangle of all samples.
+ For an empty series the rectangle is invalid.
+*/
+QRectF QwtPlotIntervalCurve::boundingRect() const
+{
+ QRectF rect = QwtPlotSeriesItem<QwtIntervalSample>::boundingRect();
+ if ( rect.isValid() && orientation() == Qt::Vertical )
+ rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
+
+ return rect;
+}
+
+/*!
+ Draw a subset of the samples
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ series will be painted to its last sample.
+
+ \sa drawTube(), drawSymbols()
+*/
+void QwtPlotIntervalCurve::drawSeries( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ if ( to < 0 )
+ to = dataSize() - 1;
+
+ if ( from < 0 )
+ from = 0;
+
+ if ( from > to )
+ return;
+
+ switch ( d_data->style )
+ {
+ case Tube:
+ drawTube( painter, xMap, yMap, canvasRect, from, to );
+ break;
+
+ case NoCurve:
+ default:
+ break;
+ }
+
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
+ {
+ drawSymbols( painter, *d_data->symbol,
+ xMap, yMap, canvasRect, from, to );
+ }
+}
+
+/*!
+ Draw a tube
+
+ Builds 2 curves from the upper and lower limits of the intervals
+ and draws them with the pen(). The area between the curves is
+ filled with the brush().
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ series will be painted to its last sample.
+
+ \sa drawSeries(), drawSymbols()
+*/
+void QwtPlotIntervalCurve::drawTube( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ painter->save();
+
+ const size_t size = to - from + 1;
+ QPolygonF polygon( 2 * size );
+ QPointF *points = polygon.data();
+
+ for ( uint i = 0; i < size; i++ )
+ {
+ QPointF &minValue = points[i];
+ QPointF &maxValue = points[2 * size - 1 - i];
+
+ const QwtIntervalSample intervalSample = sample( from + i );
+ if ( orientation() == Qt::Vertical )
+ {
+ double x = xMap.transform( intervalSample.value );
+ double y1 = yMap.transform( intervalSample.interval.minValue() );
+ double y2 = yMap.transform( intervalSample.interval.maxValue() );
+ if ( doAlign )
+ {
+ x = qRound( x );
+ y1 = qRound( y1 );
+ y2 = qRound( y2 );
+ }
+
+ minValue.rx() = x;
+ minValue.ry() = y1;
+ maxValue.rx() = x;
+ maxValue.ry() = y2;
+ }
+ else
+ {
+ double y = yMap.transform( intervalSample.value );
+ double x1 = xMap.transform( intervalSample.interval.minValue() );
+ double x2 = xMap.transform( intervalSample.interval.maxValue() );
+ if ( doAlign )
+ {
+ y = qRound( y );
+ x1 = qRound( x1 );
+ x2 = qRound( x2 );
+ }
+
+ minValue.rx() = x1;
+ minValue.ry() = y;
+ maxValue.rx() = x2;
+ maxValue.ry() = y;
+ }
+ }
+
+ if ( d_data->brush.style() != Qt::NoBrush )
+ {
+ painter->setPen( QPen( Qt::NoPen ) );
+ painter->setBrush( d_data->brush );
+
+ if ( d_data->paintAttributes & ClipPolygons )
+ {
+ const qreal m = 1.0;
+ const QPolygonF p = QwtClipper::clipPolygonF(
+ canvasRect.adjusted( -m, -m, m, m ), polygon, true );
+
+ QwtPainter::drawPolygon( painter, p );
+ }
+ else
+ {
+ QwtPainter::drawPolygon( painter, polygon );
+ }
+ }
+
+ if ( d_data->pen.style() != Qt::NoPen )
+ {
+ painter->setPen( d_data->pen );
+ painter->setBrush( Qt::NoBrush );
+
+ if ( d_data->paintAttributes & ClipPolygons )
+ {
+ qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() );
+ const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw );
+
+ QPolygonF p;
+
+ p.resize( size );
+ qMemCopy( p.data(), points, size * sizeof( QPointF ) );
+ p = QwtClipper::clipPolygonF( clipRect, p );
+ QwtPainter::drawPolyline( painter, p );
+
+ p.resize( size );
+ qMemCopy( p.data(), points + size, size * sizeof( QPointF ) );
+ p = QwtClipper::clipPolygonF( clipRect, p );
+ QwtPainter::drawPolyline( painter, p );
+ }
+ else
+ {
+ QwtPainter::drawPolyline( painter, points, size );
+ QwtPainter::drawPolyline( painter, points + size, size );
+ }
+ }
+
+ painter->restore();
+}
+
+/*!
+ Draw symbols for a subset of the samples
+
+ \param painter Painter
+ \param symbol Interval symbol
+ \param xMap x map
+ \param yMap y map
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted
+
+ \sa setSymbol(), drawSeries(), drawTube()
+*/
+void QwtPlotIntervalCurve::drawSymbols(
+ QPainter *painter, const QwtIntervalSymbol &symbol,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ painter->save();
+
+ QPen pen = symbol.pen();
+ pen.setCapStyle( Qt::FlatCap );
+
+ painter->setPen( pen );
+ painter->setBrush( symbol.brush() );
+
+ const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
+
+ const double xMin = tr.left();
+ const double xMax = tr.right();
+ const double yMin = tr.top();
+ const double yMax = tr.bottom();
+
+ const bool doClip = d_data->paintAttributes & ClipSymbol;
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QwtIntervalSample s = sample( i );
+
+ if ( orientation() == Qt::Vertical )
+ {
+ if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) )
+ {
+ const double x = xMap.transform( s.value );
+ const double y1 = yMap.transform( s.interval.minValue() );
+ const double y2 = yMap.transform( s.interval.maxValue() );
+
+ symbol.draw( painter, orientation(),
+ QPointF( x, y1 ), QPointF( x, y2 ) );
+ }
+ }
+ else
+ {
+ if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) )
+ {
+ const double y = yMap.transform( s.value );
+ const double x1 = xMap.transform( s.interval.minValue() );
+ const double x2 = xMap.transform( s.interval.maxValue() );
+
+ symbol.draw( painter, orientation(),
+ QPointF( x1, y ), QPointF( x2, y ) );
+ }
+ }
+ }
+
+ painter->restore();
+}
+
+/*!
+ \brief Draw the identifier for the legend
+
+ In case of Tube style() a plain rectangle filled with the brush() is painted.
+ If a symbol is assigned it is painted centered into rect.
+
+ \param painter Painter
+ \param rect Bounding rectangle for the identifier
+*/
+void QwtPlotIntervalCurve::drawLegendIdentifier(
+ QPainter *painter, const QRectF &rect ) const
+{
+ const double dim = qMin( rect.width(), rect.height() );
+
+ QSizeF size( dim, dim );
+
+ QRectF r( 0, 0, size.width(), size.height() );
+ r.moveCenter( rect.center() );
+
+ if ( d_data->style == Tube )
+ {
+ painter->fillRect( r, d_data->brush );
+ }
+
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
+ {
+ QPen pen = d_data->symbol->pen();
+ pen.setWidthF( pen.widthF() );
+ pen.setCapStyle( Qt::FlatCap );
+
+ painter->setPen( pen );
+ painter->setBrush( d_data->symbol->brush() );
+
+ if ( orientation() == Qt::Vertical )
+ {
+ d_data->symbol->draw( painter, orientation(),
+ QPointF( r.center().x(), r.top() ),
+ QPointF( r.center().x(), r.bottom() - 1 ) );
+ }
+ else
+ {
+ d_data->symbol->draw( painter, orientation(),
+ QPointF( r.left(), r.center().y() ),
+ QPointF( r.right() - 1, r.center().y() ) );
+ }
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_intervalcurve.h b/src/libpcp_qwt/src/qwt_plot_intervalcurve.h
new file mode 100644
index 0000000..b26586e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_intervalcurve.h
@@ -0,0 +1,130 @@
+/* -*- 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_PLOT_INTERVAL_CURVE_H
+#define QWT_PLOT_INTERVAL_CURVE_H
+
+#include "qwt_global.h"
+#include "qwt_plot_seriesitem.h"
+#include "qwt_series_data.h"
+
+class QwtIntervalSymbol;
+
+/*!
+ \brief QwtPlotIntervalCurve represents a series of samples, where each value
+ is associated with an interval ( \f$[y1,y2] = f(x)\f$ ).
+
+ The representation depends on the style() and an optional symbol()
+ that is displayed for each interval. QwtPlotIntervalCurve might be used
+ to disply error bars or the area between 2 curves.
+*/
+
+class QWT_EXPORT QwtPlotIntervalCurve: public QwtPlotSeriesItem<QwtIntervalSample>
+{
+public:
+ /*!
+ \brief Curve styles.
+ The default setting is QwtPlotIntervalCurve::Tube.
+
+ \sa setStyle(), style()
+ */
+
+ enum CurveStyle
+ {
+ /*!
+ Don't draw a curve. Note: This doesn't affect the symbols.
+ */
+ NoCurve,
+
+ /*!
+ Build 2 curves from the upper and lower limits of the intervals
+ and draw them with the pen(). The area between the curves is
+ filled with the brush().
+ */
+ Tube,
+
+ /*!
+ Styles >= QwtPlotIntervalCurve::UserCurve are reserved for derived
+ classes that overload drawSeries() with
+ additional application specific curve types.
+ */
+ UserCurve = 100
+ };
+
+ /*!
+ Attributes to modify the drawing algorithm.
+ \sa setPaintAttribute(), testPaintAttribute()
+ */
+ enum PaintAttribute
+ {
+ /*!
+ Clip polygons before painting them. In situations, where points
+ are far outside the visible area (f.e when zooming deep) this
+ might be a substantial improvement for the painting performance.
+ */
+ ClipPolygons = 0x01,
+
+ //! Check if a symbol is on the plot canvas before painting it.
+ ClipSymbol = 0x02
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ explicit QwtPlotIntervalCurve( const QString &title = QString::null );
+ explicit QwtPlotIntervalCurve( const QwtText &title );
+
+ virtual ~QwtPlotIntervalCurve();
+
+ virtual int rtti() const;
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ void setSamples( const QVector<QwtIntervalSample> & );
+
+ void setPen( const QPen & );
+ const QPen &pen() const;
+
+ void setBrush( const QBrush & );
+ const QBrush &brush() const;
+
+ void setStyle( CurveStyle style );
+ CurveStyle style() const;
+
+ void setSymbol( const QwtIntervalSymbol * );
+ const QwtIntervalSymbol *symbol() const;
+
+ virtual void drawSeries( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual QRectF boundingRect() const;
+ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const;
+
+protected:
+
+ void init();
+
+ virtual void drawTube( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ virtual void drawSymbols( QPainter *, const QwtIntervalSymbol &,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotIntervalCurve::PaintAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_item.cpp b/src/libpcp_qwt/src/qwt_plot_item.cpp
new file mode 100644
index 0000000..5ed0d40
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_item.cpp
@@ -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_plot_item.h"
+#include "qwt_text.h"
+#include "qwt_plot.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_scale_div.h"
+#include <qpainter.h>
+
+class QwtPlotItem::PrivateData
+{
+public:
+ PrivateData():
+ plot( NULL ),
+ isVisible( true ),
+ attributes( 0 ),
+ renderHints( 0 ),
+ z( 0.0 ),
+ xAxis( QwtPlot::xBottom ),
+ yAxis( QwtPlot::yLeft )
+ {
+ }
+
+ mutable QwtPlot *plot;
+
+ bool isVisible;
+ QwtPlotItem::ItemAttributes attributes;
+ QwtPlotItem::RenderHints renderHints;
+ double z;
+
+ int xAxis;
+ int yAxis;
+
+ QwtText title;
+};
+
+/*!
+ Constructor
+ \param title Title of the item
+*/
+QwtPlotItem::QwtPlotItem( const QwtText &title )
+{
+ d_data = new PrivateData;
+ d_data->title = title;
+}
+
+//! Destroy the QwtPlotItem
+QwtPlotItem::~QwtPlotItem()
+{
+ attach( NULL );
+ delete d_data;
+}
+
+/*!
+ \brief Attach the item to a plot.
+
+ This method will attach a QwtPlotItem to the QwtPlot argument. It will first
+ detach the QwtPlotItem from any plot from a previous call to attach (if
+ necessary). If a NULL argument is passed, it will detach from any QwtPlot it
+ was attached to.
+
+ \param plot Plot widget
+ \sa detach()
+*/
+void QwtPlotItem::attach( QwtPlot *plot )
+{
+ if ( plot == d_data->plot )
+ return;
+
+ // remove the item from the previous plot
+
+ if ( d_data->plot )
+ {
+ if ( d_data->plot->legend() )
+ d_data->plot->legend()->remove( this );
+
+ d_data->plot->attachItem( this, false );
+
+ if ( d_data->plot->autoReplot() )
+ d_data->plot->update();
+ }
+
+ d_data->plot = plot;
+
+ if ( d_data->plot )
+ {
+ // insert the item into the current plot
+
+ d_data->plot->attachItem( this, true );
+ itemChanged();
+ }
+}
+
+/*!
+ \brief This method detaches a QwtPlotItem from any
+ QwtPlot it has been associated with.
+
+ detach() is equivalent to calling attach( NULL )
+ \sa attach()
+*/
+void QwtPlotItem::detach()
+{
+ attach( NULL );
+}
+
+/*!
+ Return rtti for the specific class represented. QwtPlotItem is simply
+ a virtual interface class, and base classes will implement this method
+ with specific rtti values so a user can differentiate them.
+
+ The rtti value is useful for environments, where the
+ runtime type information is disabled and it is not possible
+ to do a dynamic_cast<...>.
+
+ \return rtti value
+ \sa RttiValues
+*/
+int QwtPlotItem::rtti() const
+{
+ return Rtti_PlotItem;
+}
+
+//! Return attached plot
+QwtPlot *QwtPlotItem::plot() const
+{
+ return d_data->plot;
+}
+
+/*!
+ Plot items are painted in increasing z-order.
+
+ \return setZ(), QwtPlotDict::itemList()
+*/
+double QwtPlotItem::z() const
+{
+ return d_data->z;
+}
+
+/*!
+ \brief Set the z value
+
+ Plot items are painted in increasing z-order.
+
+ \param z Z-value
+ \sa z(), QwtPlotDict::itemList()
+*/
+void QwtPlotItem::setZ( double z )
+{
+ if ( d_data->z != z )
+ {
+ if ( d_data->plot ) // update the z order
+ d_data->plot->attachItem( this, false );
+
+ d_data->z = z;
+
+ if ( d_data->plot )
+ d_data->plot->attachItem( this, true );
+
+ itemChanged();
+ }
+}
+
+/*!
+ Set a new title
+
+ \param title Title
+ \sa title()
+*/
+void QwtPlotItem::setTitle( const QString &title )
+{
+ setTitle( QwtText( title ) );
+}
+
+/*!
+ Set a new title
+
+ \param title Title
+ \sa title()
+*/
+void QwtPlotItem::setTitle( const QwtText &title )
+{
+ if ( d_data->title != title )
+ {
+ d_data->title = title;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Title of the item
+ \sa setTitle()
+*/
+const QwtText &QwtPlotItem::title() const
+{
+ return d_data->title;
+}
+
+/*!
+ Toggle an item attribute
+
+ \param attribute Attribute type
+ \param on true/false
+
+ \sa testItemAttribute(), ItemAttribute
+*/
+void QwtPlotItem::setItemAttribute( ItemAttribute attribute, bool on )
+{
+ if ( bool( d_data->attributes & attribute ) != on )
+ {
+ if ( on )
+ d_data->attributes |= attribute;
+ else
+ d_data->attributes &= ~attribute;
+
+ itemChanged();
+ }
+}
+
+/*!
+ Test an item attribute
+
+ \param attribute Attribute type
+ \return true/false
+ \sa setItemAttribute(), ItemAttribute
+*/
+bool QwtPlotItem::testItemAttribute( ItemAttribute attribute ) const
+{
+ return ( d_data->attributes & attribute );
+}
+
+/*!
+ Toggle an render hint
+
+ \param hint Render hint
+ \param on true/false
+
+ \sa testRenderHint(), RenderHint
+*/
+void QwtPlotItem::setRenderHint( RenderHint hint, bool on )
+{
+ if ( ( ( d_data->renderHints & hint ) != 0 ) != on )
+ {
+ if ( on )
+ d_data->renderHints |= hint;
+ else
+ d_data->renderHints &= ~hint;
+
+ itemChanged();
+ }
+}
+
+/*!
+ Test a render hint
+
+ \param hint Render hint
+ \return true/false
+ \sa setRenderHint(), RenderHint
+*/
+bool QwtPlotItem::testRenderHint( RenderHint hint ) const
+{
+ return ( d_data->renderHints & hint );
+}
+
+//! Show the item
+void QwtPlotItem::show()
+{
+ setVisible( true );
+}
+
+//! Hide the item
+void QwtPlotItem::hide()
+{
+ setVisible( false );
+}
+
+/*!
+ Show/Hide the item
+
+ \param on Show if true, otherwise hide
+ \sa isVisible(), show(), hide()
+*/
+void QwtPlotItem::setVisible( bool on )
+{
+ if ( on != d_data->isVisible )
+ {
+ d_data->isVisible = on;
+ itemChanged();
+ }
+}
+
+/*!
+ \return true if visible
+ \sa setVisible(), show(), hide()
+*/
+bool QwtPlotItem::isVisible() const
+{
+ return d_data->isVisible;
+}
+
+/*!
+ Update the legend and call QwtPlot::autoRefresh for the
+ parent plot.
+
+ \sa updateLegend()
+*/
+void QwtPlotItem::itemChanged()
+{
+ if ( d_data->plot )
+ {
+ if ( d_data->plot->legend() )
+ updateLegend( d_data->plot->legend() );
+
+ d_data->plot->autoRefresh();
+ }
+}
+
+/*!
+ Set X and Y axis
+
+ The item will painted according to the coordinates its Axes.
+
+ \param xAxis X Axis
+ \param yAxis Y Axis
+
+ \sa setXAxis(), setYAxis(), xAxis(), yAxis()
+*/
+void QwtPlotItem::setAxes( int xAxis, int yAxis )
+{
+ if ( xAxis == QwtPlot::xBottom || xAxis == QwtPlot::xTop )
+ d_data->xAxis = xAxis;
+
+ if ( yAxis == QwtPlot::yLeft || yAxis == QwtPlot::yRight )
+ d_data->yAxis = yAxis;
+
+ itemChanged();
+}
+
+/*!
+ Set the X axis
+
+ The item will painted according to the coordinates its Axes.
+
+ \param axis X Axis
+ \sa setAxes(), setYAxis(), xAxis()
+*/
+void QwtPlotItem::setXAxis( int axis )
+{
+ if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
+ {
+ d_data->xAxis = axis;
+ itemChanged();
+ }
+}
+
+/*!
+ Set the Y axis
+
+ The item will painted according to the coordinates its Axes.
+
+ \param axis Y Axis
+ \sa setAxes(), setXAxis(), yAxis()
+*/
+void QwtPlotItem::setYAxis( int axis )
+{
+ if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight )
+ {
+ d_data->yAxis = axis;
+ itemChanged();
+ }
+}
+
+//! Return xAxis
+int QwtPlotItem::xAxis() const
+{
+ return d_data->xAxis;
+}
+
+//! Return yAxis
+int QwtPlotItem::yAxis() const
+{
+ return d_data->yAxis;
+}
+
+/*!
+ \return An invalid bounding rect: QRectF(1.0, 1.0, -2.0, -2.0)
+*/
+QRectF QwtPlotItem::boundingRect() const
+{
+ return QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid
+}
+
+/*!
+ \brief Allocate the widget that represents the item on the legend
+
+ The default implementation returns a QwtLegendItem(), but an item
+ could be represented by any type of widget,
+ by overloading legendItem() and updateLegend().
+
+ \return QwtLegendItem()
+ \sa updateLegend() QwtLegend()
+*/
+QWidget *QwtPlotItem::legendItem() const
+{
+ QwtLegendItem *item = new QwtLegendItem;
+ if ( d_data->plot )
+ {
+ QObject::connect( item, SIGNAL( clicked() ),
+ d_data->plot, SLOT( legendItemClicked() ) );
+ QObject::connect( item, SIGNAL( checked( bool ) ),
+ d_data->plot, SLOT( legendItemChecked( bool ) ) );
+ }
+ return item;
+}
+
+/*!
+ \brief Update the widget that represents the item on the legend
+
+ updateLegend() is called from itemChanged() to adopt the widget
+ representing the item on the legend to its new configuration.
+
+ The default implementation updates a QwtLegendItem(),
+ but an item could be represented by any type of widget,
+ by overloading legendItem() and updateLegend().
+
+ \param legend Legend
+
+ \sa legendItem(), itemChanged(), QwtLegend()
+*/
+void QwtPlotItem::updateLegend( QwtLegend *legend ) const
+{
+ if ( legend == NULL )
+ return;
+
+ QWidget *lgdItem = legend->find( this );
+ if ( testItemAttribute( QwtPlotItem::Legend ) )
+ {
+ if ( lgdItem == NULL )
+ {
+ lgdItem = legendItem();
+ if ( lgdItem )
+ legend->insert( this, lgdItem );
+ }
+
+ QwtLegendItem *label = qobject_cast<QwtLegendItem *>( lgdItem );
+ if ( label )
+ {
+ // paint the identifier
+ const QSize sz = label->identifierSize();
+
+ QPixmap identifier( sz.width(), sz.height() );
+ identifier.fill( Qt::transparent );
+
+ QPainter painter( &identifier );
+ painter.setRenderHint( QPainter::Antialiasing,
+ testRenderHint( QwtPlotItem::RenderAntialiased ) );
+ drawLegendIdentifier( &painter,
+ QRect( 0, 0, sz.width(), sz.height() ) );
+ painter.end();
+
+ const bool doUpdate = label->updatesEnabled();
+ if ( doUpdate )
+ label->setUpdatesEnabled( false );
+
+ label->setText( title() );
+ label->setIdentifier( identifier );
+ label->setItemMode( legend->itemMode() );
+
+ if ( doUpdate )
+ label->setUpdatesEnabled( true );
+
+ label->update();
+ }
+ }
+ else
+ {
+ if ( lgdItem )
+ {
+ lgdItem->hide();
+ lgdItem->deleteLater();
+ }
+ }
+}
+
+/*!
+ \brief Update the item to changes of the axes scale division
+
+ Update the item, when the axes of plot have changed.
+ The default implementation does nothing, but items that depend
+ on the scale division (like QwtPlotGrid()) have to reimplement
+ updateScaleDiv()
+
+ \param xScaleDiv Scale division of the x-axis
+ \param yScaleDiv Scale division of the y-axis
+
+ \sa QwtPlot::updateAxes()
+*/
+void QwtPlotItem::updateScaleDiv( const QwtScaleDiv &xScaleDiv,
+ const QwtScaleDiv &yScaleDiv )
+{
+ Q_UNUSED( xScaleDiv );
+ Q_UNUSED( yScaleDiv );
+}
+
+/*!
+ \brief Calculate the bounding scale rect of 2 maps
+
+ \param xMap X map
+ \param yMap Y map
+
+ \return Bounding scale rect of the scale maps, not normalized
+*/
+QRectF QwtPlotItem::scaleRect( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap ) const
+{
+ return QRectF( xMap.s1(), yMap.s1(),
+ xMap.sDist(), yMap.sDist() );
+}
+
+/*!
+ \brief Calculate the bounding paint rect of 2 maps
+
+ \param xMap X map
+ \param yMap Y map
+
+ \return Bounding paint rect of the scale maps, not normalized
+*/
+QRectF QwtPlotItem::paintRect( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap ) const
+{
+ const QRectF rect( xMap.p1(), yMap.p1(),
+ xMap.pDist(), yMap.pDist() );
+
+ return rect;
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_item.h b/src/libpcp_qwt/src/qwt_plot_item.h
new file mode 100644
index 0000000..5000fff
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_item.h
@@ -0,0 +1,214 @@
+/* -*- 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_PLOT_ITEM_H
+#define QWT_PLOT_ITEM_H
+
+#include "qwt_global.h"
+#include "qwt_legend_itemmanager.h"
+#include "qwt_text.h"
+#include <qrect.h>
+
+class QString;
+class QPainter;
+class QWidget;
+class QwtPlot;
+class QwtLegend;
+class QwtScaleMap;
+class QwtScaleDiv;
+
+/*!
+ \brief Base class for items on the plot canvas
+
+ A plot item is "something", that can be painted on the plot canvas,
+ or only affects the scales of the plot widget. They can be categorized as:
+
+ - Representator\n
+ A "Representator" is an item that represents some sort of data
+ on the plot canvas. The different representator classes are organized
+ according to the characteristics of the data:
+ - QwtPlotMarker
+ Represents a point or a horizontal/vertical coordinate
+ - QwtPlotCurve
+ Represents a series of points
+ - QwtPlotSpectrogram ( QwtPlotRasterItem )
+ Represents raster data
+ - ...
+
+ - Decorators\n
+ A "Decorator" is an item, that displays additional information, that
+ is not related to any data:
+ - QwtPlotGrid
+ - QwtPlotScaleItem
+ - QwtPlotSvgItem
+ - ...
+
+ Depending on the QwtPlotItem::ItemAttribute flags, an item is included
+ into autoscaling or has an entry on the legnd.
+
+ Before misusing the existing item classes it might be better to
+ implement a new type of plot item
+ ( don't implement a watermark as spectrogram ).
+ Deriving a new type of QwtPlotItem primarily means to implement
+ the YourPlotItem::draw() method.
+
+ \sa The cpuplot example shows the implementation of additional plot items.
+*/
+
+class QWT_EXPORT QwtPlotItem: public QwtLegendItemManager
+{
+public:
+ /*!
+ \brief Runtime type information
+
+ RttiValues is used to cast plot items, without
+ having to enable runtime type information of the compiler.
+ */
+ enum RttiValues
+ {
+ //! Unspecific value, that can be used, when it doesn't matter
+ Rtti_PlotItem = 0,
+
+ //! For QwtPlotGrid
+ Rtti_PlotGrid,
+
+ //! For QwtPlotScaleItem
+ Rtti_PlotScale,
+
+ //! For QwtPlotMarker
+ Rtti_PlotMarker,
+
+ //! For QwtPlotCurve
+ Rtti_PlotCurve,
+
+ //! For QwtPlotSpectroCurve
+ Rtti_PlotSpectroCurve,
+
+ //! For QwtPlotIntervalCurve
+ Rtti_PlotIntervalCurve,
+
+ //! For QwtPlotHistogram
+ Rtti_PlotHistogram,
+
+ //! For QwtPlotSpectrogram
+ Rtti_PlotSpectrogram,
+
+ //! For QwtPlotSvgItem
+ Rtti_PlotSVG,
+
+ /*!
+ Values >= Rtti_PlotUserItem are reserved for plot items
+ not implemented in the Qwt library.
+ */
+ Rtti_PlotUserItem = 1000
+ };
+
+ /*!
+ Plot Item Attributes
+ \sa setItemAttribute(), testItemAttribute()
+ */
+ enum ItemAttribute
+ {
+ //! The item is represented on the legend.
+ Legend = 0x01,
+
+ /*!
+ The boundingRect() of the item is included in the
+ autoscaling calculation.
+ */
+ AutoScale = 0x02
+ };
+
+ //! Plot Item Attributes
+ typedef QFlags<ItemAttribute> ItemAttributes;
+
+ //! Render hints
+ enum RenderHint
+ {
+ //! Enable antialiasing
+ RenderAntialiased = 1
+ };
+
+ //! Render hints
+ typedef QFlags<RenderHint> RenderHints;
+
+ explicit QwtPlotItem( const QwtText &title = QwtText() );
+ virtual ~QwtPlotItem();
+
+ void attach( QwtPlot *plot );
+ void detach();
+
+ QwtPlot *plot() const;
+
+ void setTitle( const QString &title );
+ void setTitle( const QwtText &title );
+ const QwtText &title() const;
+
+ virtual int rtti() const;
+
+ void setItemAttribute( ItemAttribute, bool on = true );
+ bool testItemAttribute( ItemAttribute ) const;
+
+ void setRenderHint( RenderHint, bool on = true );
+ bool testRenderHint( RenderHint ) const;
+
+ double z() const;
+ void setZ( double z );
+
+ void show();
+ void hide();
+ virtual void setVisible( bool );
+ bool isVisible () const;
+
+ void setAxes( int xAxis, int yAxis );
+
+ void setXAxis( int axis );
+ int xAxis() const;
+
+ void setYAxis( int axis );
+ int yAxis() const;
+
+ virtual void itemChanged();
+
+ /*!
+ \brief Draw the item
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas in painter coordinates
+ */
+ virtual void draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const = 0;
+
+ virtual QRectF boundingRect() const;
+
+ virtual void updateLegend( QwtLegend * ) const;
+ virtual void updateScaleDiv(
+ const QwtScaleDiv&, const QwtScaleDiv& );
+
+ virtual QWidget *legendItem() const;
+
+ QRectF scaleRect( const QwtScaleMap &, const QwtScaleMap & ) const;
+ QRectF paintRect( const QwtScaleMap &, const QwtScaleMap & ) const;
+
+private:
+ // Disabled copy constructor and operator=
+ QwtPlotItem( const QwtPlotItem & );
+ QwtPlotItem &operator=( const QwtPlotItem & );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemAttributes )
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::RenderHints )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_layout.cpp b/src/libpcp_qwt/src/qwt_plot_layout.cpp
new file mode 100644
index 0000000..0e55a88
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_layout.cpp
@@ -0,0 +1,1267 @@
+/* -*- 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_plot_layout.h"
+#include "qwt_text.h"
+#include "qwt_text_label.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_widget.h"
+#include "qwt_legend.h"
+#include <qscrollbar.h>
+#include <qmath.h>
+
+class QwtPlotLayout::LayoutData
+{
+public:
+ void init( const QwtPlot *, const QRectF &rect );
+
+ struct t_legendData
+ {
+ int frameWidth;
+ int vScrollBarWidth;
+ int hScrollBarHeight;
+ QSize hint;
+ } legend;
+
+ struct t_titleData
+ {
+ QwtText text;
+ int frameWidth;
+ } title;
+
+ struct t_scaleData
+ {
+ bool isEnabled;
+ const QwtScaleWidget *scaleWidget;
+ QFont scaleFont;
+ int start;
+ int end;
+ int baseLineOffset;
+ double tickOffset;
+ int dimWithoutTitle;
+ } scale[QwtPlot::axisCnt];
+
+ struct t_canvasData
+ {
+ int frameWidth;
+ } canvas;
+};
+
+/*
+ Extract all layout relevant data from the plot components
+*/
+
+void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect )
+{
+ // legend
+
+ if ( plot->plotLayout()->legendPosition() != QwtPlot::ExternalLegend
+ && plot->legend() )
+ {
+ legend.frameWidth = plot->legend()->frameWidth();
+ legend.vScrollBarWidth =
+ plot->legend()->verticalScrollBar()->sizeHint().width();
+ legend.hScrollBarHeight =
+ plot->legend()->horizontalScrollBar()->sizeHint().height();
+
+ const QSize hint = plot->legend()->sizeHint();
+
+ int w = qMin( hint.width(), qFloor( rect.width() ) );
+ int h = plot->legend()->heightForWidth( w );
+ if ( h == 0 )
+ h = hint.height();
+
+ if ( h > rect.height() )
+ w += legend.vScrollBarWidth;
+
+ legend.hint = QSize( w, h );
+ }
+
+ // title
+
+ title.frameWidth = 0;
+ title.text = QwtText();
+
+ if ( plot->titleLabel() )
+ {
+ const QwtTextLabel *label = plot->titleLabel();
+ title.text = label->text();
+ if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) )
+ title.text.setFont( label->font() );
+
+ title.frameWidth = plot->titleLabel()->frameWidth();
+ }
+
+ // scales
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( plot->axisEnabled( axis ) )
+ {
+ const QwtScaleWidget *scaleWidget = plot->axisWidget( axis );
+
+ scale[axis].isEnabled = true;
+
+ scale[axis].scaleWidget = scaleWidget;
+
+ scale[axis].scaleFont = scaleWidget->font();
+
+ scale[axis].start = scaleWidget->startBorderDist();
+ scale[axis].end = scaleWidget->endBorderDist();
+
+ scale[axis].baseLineOffset = scaleWidget->margin();
+ scale[axis].tickOffset = scaleWidget->margin();
+ if ( scaleWidget->scaleDraw()->hasComponent(
+ QwtAbstractScaleDraw::Ticks ) )
+ {
+ scale[axis].tickOffset +=
+ scaleWidget->scaleDraw()->maxTickLength();
+ }
+
+ scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
+ QWIDGETSIZE_MAX, scale[axis].scaleFont );
+
+ if ( !scaleWidget->title().isEmpty() )
+ {
+ scale[axis].dimWithoutTitle -=
+ scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX );
+ }
+ }
+ else
+ {
+ scale[axis].isEnabled = false;
+ scale[axis].start = 0;
+ scale[axis].end = 0;
+ scale[axis].baseLineOffset = 0;
+ scale[axis].tickOffset = 0.0;
+ scale[axis].dimWithoutTitle = 0;
+ }
+ }
+
+ // canvas
+
+ canvas.frameWidth = plot->canvas()->frameWidth();
+}
+
+class QwtPlotLayout::PrivateData
+{
+public:
+ PrivateData():
+ spacing( 5 ),
+ alignCanvasToScales( false )
+ {
+ }
+
+ QRectF titleRect;
+ QRectF legendRect;
+ QRectF scaleRect[QwtPlot::axisCnt];
+ QRectF canvasRect;
+
+ QwtPlotLayout::LayoutData layoutData;
+
+ QwtPlot::LegendPosition legendPos;
+ double legendRatio;
+ unsigned int spacing;
+ unsigned int fixedOffset[QwtPlot::axisCnt];
+ unsigned int canvasMargin[QwtPlot::axisCnt];
+ bool alignCanvasToScales;
+};
+
+/*!
+ \brief Constructor
+ */
+
+QwtPlotLayout::QwtPlotLayout()
+{
+ d_data = new PrivateData;
+
+ setLegendPosition( QwtPlot::BottomLegend );
+ setFixedAxisOffset(0);
+ setCanvasMargin( 4 );
+
+ invalidate();
+}
+
+//! Destructor
+QwtPlotLayout::~QwtPlotLayout()
+{
+ delete d_data;
+}
+
+/*!
+ Change a margin of the canvas. The margin is the space
+ above/below the scale ticks. A negative margin will
+ be set to -1, excluding the borders of the scales.
+
+ \param margin New margin
+ \param axis One of QwtPlot::Axis. Specifies where the position of the margin.
+ -1 means margin at all borders.
+ \sa canvasMargin()
+
+ \warning The margin will have no effect when alignCanvasToScales is true
+*/
+
+void QwtPlotLayout::setCanvasMargin( int margin, int axis )
+{
+ if ( margin < -1 )
+ margin = -1;
+
+ if ( axis == -1 )
+ {
+ for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ d_data->canvasMargin[axis] = margin;
+ }
+ else if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->canvasMargin[axis] = margin;
+}
+
+/*!
+ \return Margin around the scale tick borders
+ \sa setCanvasMargin()
+*/
+int QwtPlotLayout::canvasMargin( int axis ) const
+{
+ if ( axis < 0 || axis >= QwtPlot::axisCnt )
+ return 0;
+
+ return d_data->canvasMargin[axis];
+}
+
+/*!
+ * Set a fixed offset for the given axis scale. The offset is the space
+ * between an outer edge of the plot widget and the scale backbone.
+ *
+ * \param offset New offset
+ * \param axis One of QwtPlot::Axis. Specifies which axis to make fixed offset.
+ * -1 means margin at all borders.
+ * \sa fixedAxisOffset()
+ * */
+void QwtPlotLayout::setFixedAxisOffset(int offset, int axis)
+{
+ if ( offset < 0 )
+ offset = 0;
+
+ if ( axis == -1 )
+ {
+ for (axis = 0; axis < QwtPlot::axisCnt; axis++)
+ d_data->fixedOffset[axis] = offset;
+ }
+ else if ( axis >= 0 || axis < QwtPlot::axisCnt )
+ d_data->fixedOffset[axis] = offset;
+}
+
+/*!
+ * \return Fixed offset, if any, for a given axis scale
+ * \sa setFixedAxisOffset()
+ * */
+int QwtPlotLayout::fixedAxisOffset(int axis) const
+{
+ if ( axis < 0 || axis >= QwtPlot::axisCnt )
+ return 0;
+
+ return d_data->fixedOffset[axis];
+}
+
+/*!
+ Change the align-canvas-to-axis-scales setting. The canvas may:
+ - extend beyond the axis scale ends to maximize its size,
+ - align with the axis scale ends to control its size.
+
+ \param alignCanvasToScales New align-canvas-to-axis-scales setting
+
+ \sa setCanvasMargin()
+ \note In this context the term 'scale' means the backbone of a scale.
+ \warning In case of alignCanvasToScales == true canvasMargin will have
+ no effect
+*/
+void QwtPlotLayout::setAlignCanvasToScales( bool alignCanvasToScales )
+{
+ d_data->alignCanvasToScales = alignCanvasToScales;
+}
+
+/*!
+ Return the align-canvas-to-axis-scales setting. The canvas may:
+ - extend beyond the axis scale ends to maximize its size
+ - align with the axis scale ends to control its size.
+
+ \return align-canvas-to-axis-scales setting
+ \sa setAlignCanvasToScales, setCanvasMargin()
+ \note In this context the term 'scale' means the backbone of a scale.
+*/
+bool QwtPlotLayout::alignCanvasToScales() const
+{
+ return d_data->alignCanvasToScales;
+}
+
+/*!
+ Change the spacing of the plot. The spacing is the distance
+ between the plot components.
+
+ \param spacing new spacing
+ \sa setMargin(), spacing()
+*/
+void QwtPlotLayout::setSpacing( int spacing )
+{
+ d_data->spacing = qMax( 0, spacing );
+}
+
+/*!
+ \return spacing
+ \sa margin(), setSpacing()
+*/
+int QwtPlotLayout::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ \brief Specify the position of the legend
+ \param pos The legend's position.
+ \param ratio Ratio between legend and the bounding rect
+ of title, canvas and axes. The legend will be shrinked
+ if it would need more space than the given ratio.
+ The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
+ it will be reset to the default ratio.
+ The default vertical/horizontal ratio is 0.33/0.5.
+
+ \sa QwtPlot::setLegendPosition()
+*/
+
+void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio )
+{
+ if ( ratio > 1.0 )
+ ratio = 1.0;
+
+ switch ( pos )
+ {
+ case QwtPlot::TopLegend:
+ case QwtPlot::BottomLegend:
+ if ( ratio <= 0.0 )
+ ratio = 0.33;
+ d_data->legendRatio = ratio;
+ d_data->legendPos = pos;
+ break;
+ case QwtPlot::LeftLegend:
+ case QwtPlot::RightLegend:
+ if ( ratio <= 0.0 )
+ ratio = 0.5;
+ d_data->legendRatio = ratio;
+ d_data->legendPos = pos;
+ break;
+ case QwtPlot::ExternalLegend:
+ d_data->legendRatio = ratio; // meaningless
+ d_data->legendPos = pos;
+ default:
+ break;
+ }
+}
+
+/*!
+ \brief Specify the position of the legend
+ \param pos The legend's position. Valid values are
+ \c QwtPlot::LeftLegend, \c QwtPlot::RightLegend,
+ \c QwtPlot::TopLegend, \c QwtPlot::BottomLegend.
+
+ \sa QwtPlot::setLegendPosition()
+*/
+void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos )
+{
+ setLegendPosition( pos, 0.0 );
+}
+
+/*!
+ \return Position of the legend
+ \sa setLegendPosition(), QwtPlot::setLegendPosition(),
+ QwtPlot::legendPosition()
+*/
+QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
+{
+ return d_data->legendPos;
+}
+
+/*!
+ Specify the relative size of the legend in the plot
+ \param ratio Ratio between legend and the bounding rect
+ of title, canvas and axes. The legend will be shrinked
+ if it would need more space than the given ratio.
+ The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
+ it will be reset to the default ratio.
+ The default vertical/horizontal ratio is 0.33/0.5.
+*/
+void QwtPlotLayout::setLegendRatio( double ratio )
+{
+ setLegendPosition( legendPosition(), ratio );
+}
+
+/*!
+ \return The relative size of the legend in the plot.
+ \sa setLegendPosition()
+*/
+double QwtPlotLayout::legendRatio() const
+{
+ return d_data->legendRatio;
+}
+
+/*!
+ \return Geometry for the title
+ \sa activate(), invalidate()
+*/
+const QRectF &QwtPlotLayout::titleRect() const
+{
+ return d_data->titleRect;
+}
+
+/*!
+ \return Geometry for the legend
+ \sa activate(), invalidate()
+*/
+const QRectF &QwtPlotLayout::legendRect() const
+{
+ return d_data->legendRect;
+}
+
+/*!
+ \param axis Axis index
+ \return Geometry for the scale
+ \sa activate(), invalidate()
+*/
+const QRectF &QwtPlotLayout::scaleRect( int axis ) const
+{
+ if ( axis < 0 || axis >= QwtPlot::axisCnt )
+ {
+ static QRectF dummyRect;
+ return dummyRect;
+ }
+ return d_data->scaleRect[axis];
+}
+
+/*!
+ \return Geometry for the canvas
+ \sa activate(), invalidate()
+*/
+const QRectF &QwtPlotLayout::canvasRect() const
+{
+ return d_data->canvasRect;
+}
+
+/*!
+ Invalidate the geometry of all components.
+ \sa activate()
+*/
+void QwtPlotLayout::invalidate()
+{
+ d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ d_data->scaleRect[axis] = QRect();
+}
+
+/*!
+ \brief Return a minimum size hint
+ \sa QwtPlot::minimumSizeHint()
+*/
+
+QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const
+{
+ class ScaleData
+ {
+ public:
+ ScaleData()
+ {
+ w = h = minLeft = minRight = tickOffset = 0;
+ }
+
+ int w;
+ int h;
+ int minLeft;
+ int minRight;
+ int tickOffset;
+ } scaleData[QwtPlot::axisCnt];
+
+ int canvasBorder[QwtPlot::axisCnt];
+
+ int axis;
+ for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( plot->axisEnabled( axis ) )
+ {
+ const QwtScaleWidget *scl = plot->axisWidget( axis );
+ ScaleData &sd = scaleData[axis];
+
+ const QSize hint = scl->minimumSizeHint();
+ sd.w = hint.width();
+ sd.h = hint.height();
+ scl->getBorderDistHint( sd.minLeft, sd.minRight );
+ sd.tickOffset = scl->margin();
+ if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ sd.tickOffset += qCeil( scl->scaleDraw()->maxTickLength() );
+ }
+
+ canvasBorder[axis] = plot->canvas()->frameWidth() +
+ d_data->canvasMargin[axis] + 1;
+
+ }
+
+
+ for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ ScaleData &sd = scaleData[axis];
+ if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) )
+ {
+ if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] )
+ && scaleData[QwtPlot::yLeft].w )
+ {
+ int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
+ if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
+ shiftLeft = scaleData[QwtPlot::yLeft].w;
+
+ sd.w -= shiftLeft;
+ }
+ if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] )
+ && scaleData[QwtPlot::yRight].w )
+ {
+ int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
+ if ( shiftRight > scaleData[QwtPlot::yRight].w )
+ shiftRight = scaleData[QwtPlot::yRight].w;
+
+ sd.w -= shiftRight;
+ }
+ }
+
+ if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) )
+ {
+ if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) &&
+ scaleData[QwtPlot::xBottom].h )
+ {
+ int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
+ if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
+ shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
+
+ sd.h -= shiftBottom;
+ }
+ if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) &&
+ scaleData[QwtPlot::xTop].h )
+ {
+ int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
+ if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
+ shiftTop = scaleData[QwtPlot::xTop].tickOffset;
+
+ sd.h -= shiftTop;
+ }
+ }
+ }
+
+ const QwtPlotCanvas *canvas = plot->canvas();
+ const QSize minCanvasSize = canvas->minimumSize();
+
+ int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
+ int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w )
+ + 2 * ( canvas->frameWidth() + 1 );
+ w += qMax( cw, minCanvasSize.width() );
+
+ int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
+ int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h )
+ + 2 * ( canvas->frameWidth() + 1 );
+ h += qMax( ch, minCanvasSize.height() );
+
+ const QwtTextLabel *title = plot->titleLabel();
+ if ( title && !title->text().isEmpty() )
+ {
+ // If only QwtPlot::yLeft or QwtPlot::yRight is showing,
+ // we center on the plot canvas.
+ const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft )
+ && plot->axisEnabled( QwtPlot::yRight ) );
+
+ int titleW = w;
+ if ( centerOnCanvas )
+ {
+ titleW -= scaleData[QwtPlot::yLeft].w
+ + scaleData[QwtPlot::yRight].w;
+ }
+
+ int titleH = title->heightForWidth( titleW );
+ if ( titleH > titleW ) // Compensate for a long title
+ {
+ w = titleW = titleH;
+ if ( centerOnCanvas )
+ {
+ w += scaleData[QwtPlot::yLeft].w
+ + scaleData[QwtPlot::yRight].w;
+ }
+
+ titleH = title->heightForWidth( titleW );
+ }
+ h += titleH + d_data->spacing;
+ }
+
+ // Compute the legend contribution
+
+ const QwtLegend *legend = plot->legend();
+ if ( d_data->legendPos != QwtPlot::ExternalLegend
+ && legend && !legend->isEmpty() )
+ {
+ if ( d_data->legendPos == QwtPlot::LeftLegend
+ || d_data->legendPos == QwtPlot::RightLegend )
+ {
+ int legendW = legend->sizeHint().width();
+ int legendH = legend->heightForWidth( legendW );
+
+ if ( legend->frameWidth() > 0 )
+ w += d_data->spacing;
+
+ if ( legendH > h )
+ legendW += legend->verticalScrollBar()->sizeHint().width();
+
+ if ( d_data->legendRatio < 1.0 )
+ legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) );
+
+ w += legendW + d_data->spacing;
+ }
+ else // QwtPlot::Top, QwtPlot::Bottom
+ {
+ int legendW = qMin( legend->sizeHint().width(), w );
+ int legendH = legend->heightForWidth( legendW );
+
+ if ( legend->frameWidth() > 0 )
+ h += d_data->spacing;
+
+ if ( d_data->legendRatio < 1.0 )
+ legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) );
+
+ h += legendH + d_data->spacing;
+ }
+ }
+
+ return QSize( w, h );
+}
+
+/*!
+ Find the geometry for the legend
+ \param options Options how to layout the legend
+ \param rect Rectangle where to place the legend
+ \return Geometry for the legend
+ \sa Options
+*/
+
+QRectF QwtPlotLayout::layoutLegend( Options options,
+ const QRectF &rect ) const
+{
+ const QSize hint( d_data->layoutData.legend.hint );
+
+ int dim;
+ if ( d_data->legendPos == QwtPlot::LeftLegend
+ || d_data->legendPos == QwtPlot::RightLegend )
+ {
+ // We don't allow vertical legends to take more than
+ // half of the available space.
+
+ dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) );
+
+ if ( !( options & IgnoreScrollbars ) )
+ {
+ if ( hint.height() > rect.height() )
+ {
+ // The legend will need additional
+ // space for the vertical scrollbar.
+
+ dim += d_data->layoutData.legend.vScrollBarWidth;
+ }
+ }
+ }
+ else
+ {
+ dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) );
+ dim = qMax( dim, d_data->layoutData.legend.hScrollBarHeight );
+ }
+
+ QRectF legendRect = rect;
+ switch ( d_data->legendPos )
+ {
+ case QwtPlot::LeftLegend:
+ legendRect.setWidth( dim );
+ break;
+ case QwtPlot::RightLegend:
+ legendRect.setX( rect.right() - dim );
+ legendRect.setWidth( dim );
+ break;
+ case QwtPlot::TopLegend:
+ legendRect.setHeight( dim );
+ break;
+ case QwtPlot::BottomLegend:
+ legendRect.setY( rect.bottom() - dim );
+ legendRect.setHeight( dim );
+ break;
+ case QwtPlot::ExternalLegend:
+ break;
+ }
+
+ return legendRect;
+}
+
+/*!
+ Align the legend to the canvas
+ \param canvasRect Geometry of the canvas
+ \param legendRect Maximum geometry for the legend
+ \return Geometry for the aligned legend
+*/
+QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect,
+ const QRectF &legendRect ) const
+{
+ QRectF alignedRect = legendRect;
+
+ if ( d_data->legendPos == QwtPlot::BottomLegend
+ || d_data->legendPos == QwtPlot::TopLegend )
+ {
+ if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
+ {
+ alignedRect.setX( canvasRect.x() );
+ alignedRect.setWidth( canvasRect.width() );
+ }
+ }
+ else
+ {
+ if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
+ {
+ alignedRect.setY( canvasRect.y() );
+ alignedRect.setHeight( canvasRect.height() );
+ }
+ }
+
+ return alignedRect;
+}
+
+/*!
+ Expand all line breaks in text labels, and calculate the height
+ of their widgets in orientation of the text.
+
+ \param options Options how to layout the legend
+ \param rect Bounding rect for title, axes and canvas.
+ \param dimTitle Expanded height of the title widget
+ \param dimAxis Expanded heights of the axis in axis orientation.
+
+ \sa Options
+*/
+void QwtPlotLayout::expandLineBreaks( int options, const QRectF &rect,
+ int &dimTitle, int dimAxis[QwtPlot::axisCnt] ) const
+{
+ dimTitle = 0;
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ dimAxis[axis] = 0;
+
+ int backboneOffset[QwtPlot::axisCnt];
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ backboneOffset[axis] = 0;
+ if ( !d_data->alignCanvasToScales )
+ backboneOffset[axis] += d_data->canvasMargin[axis];
+ if ( !( options & IgnoreFrames ) )
+ backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
+ }
+
+ bool done = false;
+ while ( !done )
+ {
+ done = true;
+
+ // the size for the 4 axis depend on each other. Expanding
+ // the height of a horizontal axis will shrink the height
+ // for the vertical axis, shrinking the height of a vertical
+ // axis will result in a line break what will expand the
+ // width and results in shrinking the width of a horizontal
+ // axis what might result in a line break of a horizontal
+ // axis ... . So we loop as long until no size changes.
+
+ if ( !d_data->layoutData.title.text.isEmpty() )
+ {
+ double w = rect.width();
+
+ if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
+ != d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
+ {
+ // center to the canvas
+ w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
+ }
+
+ int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) );
+ if ( !( options & IgnoreFrames ) )
+ d += 2 * d_data->layoutData.title.frameWidth;
+
+ if ( d > dimTitle )
+ {
+ dimTitle = d;
+ done = false;
+ }
+ }
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ const struct LayoutData::t_scaleData &scaleData =
+ d_data->layoutData.scale[axis];
+
+ if ( scaleData.isEnabled )
+ {
+ double length;
+ if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
+ {
+ length = rect.width() - dimAxis[QwtPlot::yLeft]
+ - dimAxis[QwtPlot::yRight];
+ length -= scaleData.start + scaleData.end;
+
+ if ( dimAxis[QwtPlot::yRight] > 0 )
+ length -= 1;
+
+ length += qMin( dimAxis[QwtPlot::yLeft],
+ scaleData.start - backboneOffset[QwtPlot::yLeft] );
+ length += qMin( dimAxis[QwtPlot::yRight],
+ scaleData.end - backboneOffset[QwtPlot::yRight] );
+ }
+ else // QwtPlot::yLeft, QwtPlot::yRight
+ {
+ length = rect.height() - dimAxis[QwtPlot::xTop]
+ - dimAxis[QwtPlot::xBottom];
+ length -= scaleData.start + scaleData.end;
+ length -= 1;
+
+ if ( dimAxis[QwtPlot::xBottom] <= 0 )
+ length -= 1;
+ if ( dimAxis[QwtPlot::xTop] <= 0 )
+ length -= 1;
+
+ if ( dimAxis[QwtPlot::xBottom] > 0 )
+ {
+ length += qMin(
+ d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
+ double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) );
+ }
+ if ( dimAxis[QwtPlot::xTop] > 0 )
+ {
+ length += qMin(
+ d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
+ double( scaleData.end - backboneOffset[QwtPlot::xTop] ) );
+ }
+
+ if ( dimTitle > 0 )
+ length -= dimTitle + d_data->spacing;
+ }
+
+ if (d_data->fixedOffset[axis])
+ {
+ dimAxis[axis] = d_data->fixedOffset[axis]
+ + backboneOffset[QwtPlot::yLeft];
+ continue;
+ }
+
+ int d = scaleData.dimWithoutTitle;
+ if ( !scaleData.scaleWidget->title().isEmpty() )
+ {
+ d += scaleData.scaleWidget->titleHeightForWidth( qFloor( length ) );
+ }
+
+
+ if ( d > dimAxis[axis] )
+ {
+ dimAxis[axis] = d;
+ done = false;
+ }
+ }
+ }
+ }
+}
+
+/*!
+ Align the ticks of the axis to the canvas borders using
+ the empty corners.
+
+ \sa Options
+*/
+
+void QwtPlotLayout::alignScales( int options,
+ QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const
+{
+ int backboneOffset[QwtPlot::axisCnt];
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ backboneOffset[axis] = 0;
+ if ( !d_data->alignCanvasToScales )
+ backboneOffset[axis] += d_data->canvasMargin[axis];
+ if ( !( options & IgnoreFrames ) )
+ backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
+ }
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( !scaleRect[axis].isValid() )
+ continue;
+
+ const int startDist = d_data->layoutData.scale[axis].start;
+ const int endDist = d_data->layoutData.scale[axis].end;
+
+ QRectF &axisRect = scaleRect[axis];
+
+ if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
+ {
+ const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft];
+ const int leftOffset =
+ backboneOffset[QwtPlot::yLeft] - startDist;
+
+ if ( leftScaleRect.isValid() )
+ {
+ const double dx = leftOffset + leftScaleRect.width();
+ if ( d_data->alignCanvasToScales && dx < 0.0 )
+ {
+ /*
+ The axis needs more space than the width
+ of the left scale.
+ */
+ const double cLeft = canvasRect.left(); // qreal -> double
+ canvasRect.setLeft( qMax( cLeft, axisRect.left() - dx ) );
+ }
+ else
+ {
+ const double minLeft = leftScaleRect.left();
+ const double left = axisRect.left() + leftOffset;
+ axisRect.setLeft( qMax( left, minLeft ) );
+ }
+ }
+ else
+ {
+ if ( d_data->alignCanvasToScales && leftOffset < 0 )
+ {
+ canvasRect.setLeft( qMax( canvasRect.left(),
+ axisRect.left() - leftOffset ) );
+ }
+ else
+ {
+ if ( leftOffset > 0 )
+ axisRect.setLeft( axisRect.left() + leftOffset );
+ }
+ }
+
+ const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight];
+ const int rightOffset =
+ backboneOffset[QwtPlot::yRight] - endDist + 1;
+
+ if ( rightScaleRect.isValid() )
+ {
+ const double dx = rightOffset + rightScaleRect.width();
+ if ( d_data->alignCanvasToScales && dx < 0 )
+ {
+ /*
+ The axis needs more space than the width
+ of the right scale.
+ */
+ const double cRight = canvasRect.right(); // qreal -> double
+ canvasRect.setRight( qMin( cRight, axisRect.right() + dx ) );
+ }
+
+ const double maxRight = rightScaleRect.right();
+ const double right = axisRect.right() - rightOffset;
+ axisRect.setRight( qMin( right, maxRight ) );
+ }
+ else
+ {
+ if ( d_data->alignCanvasToScales && rightOffset < 0 )
+ {
+ canvasRect.setRight( qMin( canvasRect.right(),
+ axisRect.right() + rightOffset ) );
+ }
+ else
+ {
+ if ( rightOffset > 0 )
+ axisRect.setRight( axisRect.right() - rightOffset );
+ }
+ }
+ }
+ else // QwtPlot::yLeft, QwtPlot::yRight
+ {
+ const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom];
+ const int bottomOffset =
+ backboneOffset[QwtPlot::xBottom] - endDist + 1;
+
+ if ( bottomScaleRect.isValid() )
+ {
+ const double dy = bottomOffset + bottomScaleRect.height();
+ if ( d_data->alignCanvasToScales && dy < 0 )
+ {
+ /*
+ The axis needs more space than the height
+ of the bottom scale.
+ */
+ const double cBottom = canvasRect.bottom(); // qreal -> double
+ canvasRect.setBottom( qMin( cBottom, axisRect.bottom() + dy ) );
+ }
+ else
+ {
+ const double maxBottom = bottomScaleRect.top() +
+ d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
+ const double bottom = axisRect.bottom() - bottomOffset;
+ axisRect.setBottom( qMin( bottom, maxBottom ) );
+ }
+ }
+ else
+ {
+ if ( d_data->alignCanvasToScales && bottomOffset < 0 )
+ {
+ canvasRect.setBottom( qMin( canvasRect.bottom(),
+ axisRect.bottom() + bottomOffset ) );
+ }
+ else
+ {
+ if ( bottomOffset > 0 )
+ axisRect.setBottom( axisRect.bottom() - bottomOffset );
+ }
+ }
+
+ const QRectF &topScaleRect = scaleRect[QwtPlot::xTop];
+ const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
+
+ if ( topScaleRect.isValid() )
+ {
+ const double dy = topOffset + topScaleRect.height();
+ if ( d_data->alignCanvasToScales && dy < 0 )
+ {
+ /*
+ The axis needs more space than the height
+ of the top scale.
+ */
+ const double cTop = canvasRect.top(); // qreal -> double
+ canvasRect.setTop( qMax( cTop, axisRect.top() - dy ) );
+ }
+ else
+ {
+ const double minTop = topScaleRect.bottom() -
+ d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
+ const double top = axisRect.top() + topOffset;
+ axisRect.setTop( qMax( top, minTop ) );
+ }
+ }
+ else
+ {
+ if ( d_data->alignCanvasToScales && topOffset < 0 )
+ {
+ canvasRect.setTop( qMax( canvasRect.top(),
+ axisRect.top() - topOffset ) );
+ }
+ else
+ {
+ if ( topOffset > 0 )
+ axisRect.setTop( axisRect.top() + topOffset );
+ }
+ }
+ }
+ }
+
+ if ( d_data->alignCanvasToScales )
+ {
+ /*
+ The canvas has been aligned to the scale with largest
+ border distances. Now we have to realign the other scale.
+ */
+
+ int fw = 0;
+ if ( !( options & IgnoreFrames ) )
+ fw = d_data->layoutData.canvas.frameWidth;
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( !scaleRect[axis].isValid() )
+ continue;
+
+ if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
+ {
+ scaleRect[axis].setLeft( canvasRect.left() + fw
+ - d_data->layoutData.scale[axis].start );
+ scaleRect[axis].setRight( canvasRect.right() - fw - 1
+ + d_data->layoutData.scale[axis].end );
+ }
+ else
+ {
+ scaleRect[axis].setTop( canvasRect.top() + fw
+ - d_data->layoutData.scale[axis].start );
+ scaleRect[axis].setBottom( canvasRect.bottom() - fw - 1
+ + d_data->layoutData.scale[axis].end );
+ }
+ }
+
+ if ( scaleRect[QwtPlot::xTop].isValid() )
+ scaleRect[QwtPlot::xTop].setBottom( canvasRect.top() );
+ if ( scaleRect[QwtPlot::xBottom].isValid() )
+ scaleRect[QwtPlot::xBottom].setTop( canvasRect.bottom() );
+ if ( scaleRect[QwtPlot::yLeft].isValid() )
+ scaleRect[QwtPlot::yLeft].setRight( canvasRect.left() );
+ if ( scaleRect[QwtPlot::yRight].isValid() )
+ scaleRect[QwtPlot::yRight].setLeft( canvasRect.right() );
+ }
+}
+
+/*!
+ \brief Recalculate the geometry of all components.
+
+ \param plot Plot to be layout
+ \param plotRect Rect where to place the components
+ \param options Layout options
+
+ \sa invalidate(), titleRect(),
+ legendRect(), scaleRect(), canvasRect()
+*/
+void QwtPlotLayout::activate( const QwtPlot *plot,
+ const QRectF &plotRect, Options options )
+{
+ invalidate();
+
+ QRectF rect( plotRect ); // undistributed rest of the plot rect
+
+ // We extract all layout relevant data from the widgets,
+ // filter them through pfilter and save them to d_data->layoutData.
+
+ d_data->layoutData.init( plot, rect );
+
+ if ( !( options & IgnoreLegend )
+ && d_data->legendPos != QwtPlot::ExternalLegend
+ && plot->legend() && !plot->legend()->isEmpty() )
+ {
+ d_data->legendRect = layoutLegend( options, rect );
+
+ // subtract d_data->legendRect from rect
+
+ const QRegion region( rect.toRect() );
+ rect = region.subtract( d_data->legendRect.toRect() ).boundingRect();
+
+ switch ( d_data->legendPos )
+ {
+ case QwtPlot::LeftLegend:
+ rect.setLeft( rect.left() + d_data->spacing );
+ break;
+ case QwtPlot::RightLegend:
+ rect.setRight( rect.right() - d_data->spacing );
+ break;
+ case QwtPlot::TopLegend:
+ rect.setTop( rect.top() + d_data->spacing );
+ break;
+ case QwtPlot::BottomLegend:
+ rect.setBottom( rect.bottom() - d_data->spacing );
+ break;
+ case QwtPlot::ExternalLegend:
+ break; // suppress compiler warning
+ }
+ }
+
+ /*
+ +---+-----------+---+
+ | Title |
+ +---+-----------+---+
+ | | Axis | |
+ +---+-----------+---+
+ | A | | A |
+ | x | Canvas | x |
+ | i | | i |
+ | s | | s |
+ +---+-----------+---+
+ | | Axis | |
+ +---+-----------+---+
+ */
+
+ // axes and title include text labels. The height of each
+ // label depends on its line breaks, that depend on the width
+ // for the label. A line break in a horizontal text will reduce
+ // the available width for vertical texts and vice versa.
+ // expandLineBreaks finds the height/width for title and axes
+ // including all line breaks.
+
+ int dimTitle, dimAxes[QwtPlot::axisCnt];
+ expandLineBreaks( options, rect, dimTitle, dimAxes );
+
+ if ( dimTitle > 0 )
+ {
+ d_data->titleRect.setRect(
+ rect.left(), rect.top(), rect.width(), dimTitle );
+
+ if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
+ d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
+ {
+ // if only one of the y axes is missing we align
+ // the title centered to the canvas
+
+ d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] );
+ d_data->titleRect.setWidth( rect.width()
+ - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
+ }
+
+ // subtract title
+ rect.setTop( rect.top() + dimTitle + d_data->spacing );
+ }
+
+ d_data->canvasRect.setRect(
+ rect.x() + dimAxes[QwtPlot::yLeft],
+ rect.y() + dimAxes[QwtPlot::xTop],
+ rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
+ rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] );
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ // set the rects for the axes
+
+ if ( dimAxes[axis] )
+ {
+ int dim = dimAxes[axis];
+ QRectF &scaleRect = d_data->scaleRect[axis];
+
+ scaleRect = d_data->canvasRect;
+ switch ( axis )
+ {
+ case QwtPlot::yLeft:
+ scaleRect.setX( d_data->canvasRect.left() - dim );
+ scaleRect.setWidth( dim );
+ break;
+ case QwtPlot::yRight:
+ scaleRect.setX( d_data->canvasRect.right() );
+ scaleRect.setWidth( dim );
+ break;
+ case QwtPlot::xBottom:
+ scaleRect.setY( d_data->canvasRect.bottom() );
+ scaleRect.setHeight( dim );
+ break;
+ case QwtPlot::xTop:
+ scaleRect.setY( d_data->canvasRect.top() - dim );
+ scaleRect.setHeight( dim );
+ break;
+ }
+ scaleRect = scaleRect.normalized();
+ }
+ }
+
+ // +---+-----------+---+
+ // | <- Axis -> |
+ // +-^-+-----------+-^-+
+ // | | | | | |
+ // | | | |
+ // | A | | A |
+ // | x | Canvas | x |
+ // | i | | i |
+ // | s | | s |
+ // | | | |
+ // | | | | | |
+ // +-V-+-----------+-V-+
+ // | <- Axis -> |
+ // +---+-----------+---+
+
+ // The ticks of the axes - not the labels above - should
+ // be aligned to the canvas. So we try to use the empty
+ // corners to extend the axes, so that the label texts
+ // left/right of the min/max ticks are moved into them.
+
+ alignScales( options, d_data->canvasRect, d_data->scaleRect );
+
+ if ( !d_data->legendRect.isEmpty() )
+ {
+ // We prefer to align the legend to the canvas - not to
+ // the complete plot - if possible.
+
+ d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect );
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_layout.h b/src/libpcp_qwt/src/qwt_plot_layout.h
new file mode 100644
index 0000000..2d9348d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_layout.h
@@ -0,0 +1,108 @@
+/* -*- 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_PLOT_LAYOUT_H
+#define QWT_PLOT_LAYOUT_H
+
+#include "qwt_global.h"
+#include "qwt_plot.h"
+
+/*!
+ \brief Layout engine for QwtPlot.
+
+ It is used by the QwtPlot widget to organize its internal widgets
+ or by QwtPlot::print() to render its content to a QPaintDevice like
+ a QPrinter, QPixmap/QImage or QSvgRenderer.
+*/
+
+class QWT_EXPORT QwtPlotLayout
+{
+public:
+ /*!
+ Options to configure the plot layout engine
+ \sa activate(), QwtPlotRenderer
+ */
+ enum Option
+ {
+ //! Unused
+ AlignScales = 0x01,
+
+ /*!
+ Ignore the dimension of the scrollbars. There are no
+ scrollbars, when the plot is not rendered to widgets.
+ */
+ IgnoreScrollbars = 0x02,
+
+ //! Ignore all frames.
+ IgnoreFrames = 0x04,
+
+ //! Ignore the legend.
+ IgnoreLegend = 0x08
+ };
+
+ //! Layout options
+ typedef QFlags<Option> Options;
+
+ explicit QwtPlotLayout();
+ virtual ~QwtPlotLayout();
+
+ void setCanvasMargin( int margin, int axis = -1 );
+ int canvasMargin( int axis ) const;
+
+ void setFixedAxisOffset(int offset, int axis = -1);
+ int fixedAxisOffset(int axis) const;
+
+ void setAlignCanvasToScales( bool );
+ bool alignCanvasToScales() const;
+
+ void setSpacing( int );
+ int spacing() const;
+
+ void setLegendPosition( QwtPlot::LegendPosition pos, double ratio );
+ void setLegendPosition( QwtPlot::LegendPosition pos );
+ QwtPlot::LegendPosition legendPosition() const;
+
+ void setLegendRatio( double ratio );
+ double legendRatio() const;
+
+ virtual QSize minimumSizeHint( const QwtPlot * ) const;
+
+ virtual void activate( const QwtPlot *,
+ const QRectF &rect, Options options = 0x00 );
+
+ virtual void invalidate();
+
+ const QRectF &titleRect() const;
+ const QRectF &legendRect() const;
+ const QRectF &scaleRect( int axis ) const;
+ const QRectF &canvasRect() const;
+
+ class LayoutData;
+
+protected:
+
+ QRectF layoutLegend( Options options, const QRectF & ) const;
+ QRectF alignLegend( const QRectF &canvasRect,
+ const QRectF &legendRect ) const;
+
+ void expandLineBreaks( int options, const QRectF &rect,
+ int &dimTitle, int dimAxes[QwtPlot::axisCnt] ) const;
+
+ void alignScales( int options, QRectF &canvasRect,
+ QRectF scaleRect[QwtPlot::axisCnt] ) const;
+
+private:
+ class PrivateData;
+
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotLayout::Options )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_magnifier.cpp b/src/libpcp_qwt/src/qwt_plot_magnifier.cpp
new file mode 100644
index 0000000..b490d80
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_magnifier.cpp
@@ -0,0 +1,143 @@
+/* -*- 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_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_div.h"
+#include "qwt_plot_magnifier.h"
+#include <qevent.h>
+
+class QwtPlotMagnifier::PrivateData
+{
+public:
+ PrivateData()
+ {
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ isAxisEnabled[axis] = true;
+ }
+
+ bool isAxisEnabled[QwtPlot::axisCnt];
+};
+
+/*!
+ Constructor
+ \param canvas Plot canvas to be magnified
+*/
+QwtPlotMagnifier::QwtPlotMagnifier( QwtPlotCanvas *canvas ):
+ QwtMagnifier( canvas )
+{
+ d_data = new PrivateData();
+}
+
+//! Destructor
+QwtPlotMagnifier::~QwtPlotMagnifier()
+{
+ delete d_data;
+}
+
+/*!
+ \brief En/Disable an axis
+
+ Only Axes that are enabled will be zoomed.
+ All other axes will remain unchanged.
+
+ \param axis Axis, see QwtPlot::Axis
+ \param on On/Off
+
+ \sa isAxisEnabled()
+*/
+void QwtPlotMagnifier::setAxisEnabled( int axis, bool on )
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->isAxisEnabled[axis] = on;
+}
+
+/*!
+ Test if an axis is enabled
+
+ \param axis Axis, see QwtPlot::Axis
+ \return True, if the axis is enabled
+
+ \sa setAxisEnabled()
+*/
+bool QwtPlotMagnifier::isAxisEnabled( int axis ) const
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ return d_data->isAxisEnabled[axis];
+
+ return true;
+}
+
+//! Return observed plot canvas
+QwtPlotCanvas *QwtPlotMagnifier::canvas()
+{
+ return qobject_cast<QwtPlotCanvas *>( parent() );
+}
+
+//! Return Observed plot canvas
+const QwtPlotCanvas *QwtPlotMagnifier::canvas() const
+{
+ return qobject_cast<const QwtPlotCanvas *>( parent() );
+}
+
+//! Return plot widget, containing the observed plot canvas
+QwtPlot *QwtPlotMagnifier::plot()
+{
+ QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+//! Return plot widget, containing the observed plot canvas
+const QwtPlot *QwtPlotMagnifier::plot() const
+{
+ const QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+/*!
+ Zoom in/out the axes scales
+ \param factor A value < 1.0 zooms in, a value > 1.0 zooms out.
+*/
+void QwtPlotMagnifier::rescale( double factor )
+{
+ factor = qAbs( factor );
+ if ( factor == 1.0 || factor == 0.0 )
+ return;
+
+ bool doReplot = false;
+ QwtPlot* plt = plot();
+
+ const bool autoReplot = plt->autoReplot();
+ plt->setAutoReplot( false );
+
+ for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
+ {
+ const QwtScaleDiv *scaleDiv = plt->axisScaleDiv( axisId );
+ if ( isAxisEnabled( axisId ) && scaleDiv->isValid() )
+ {
+ const double center =
+ scaleDiv->lowerBound() + scaleDiv->range() / 2;
+ const double width_2 = scaleDiv->range() / 2 * factor;
+
+ plt->setAxisScale( axisId, center - width_2, center + width_2 );
+ doReplot = true;
+ }
+ }
+
+ plt->setAutoReplot( autoReplot );
+
+ if ( doReplot )
+ plt->replot();
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_magnifier.h b/src/libpcp_qwt/src/qwt_plot_magnifier.h
new file mode 100644
index 0000000..e7369c7
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_magnifier.h
@@ -0,0 +1,55 @@
+/* -*- 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_PLOT_MAGNIFIER_H
+#define QWT_PLOT_MAGNIFIER_H 1
+
+#include "qwt_global.h"
+#include "qwt_magnifier.h"
+
+class QwtPlotCanvas;
+class QwtPlot;
+
+/*!
+ \brief QwtPlotMagnifier provides zooming, by magnifying in steps.
+
+ Using QwtPlotMagnifier a plot can be zoomed in/out in steps using
+ keys, the mouse wheel or moving a mouse button in vertical direction.
+
+ Together with QwtPlotZoomer and QwtPlotPanner it is possible to implement
+ individual and powerful navigation of the plot canvas.
+
+ \sa QwtPlotZoomer, QwtPlotPanner, QwtPlot
+*/
+class QWT_EXPORT QwtPlotMagnifier: public QwtMagnifier
+{
+ Q_OBJECT
+
+public:
+ explicit QwtPlotMagnifier( QwtPlotCanvas * );
+ virtual ~QwtPlotMagnifier();
+
+ void setAxisEnabled( int axis, bool on );
+ bool isAxisEnabled( int axis ) const;
+
+ QwtPlotCanvas *canvas();
+ const QwtPlotCanvas *canvas() const;
+
+ QwtPlot *plot();
+ const QwtPlot *plot() const;
+
+protected:
+ virtual void rescale( double factor );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_marker.cpp b/src/libpcp_qwt/src/qwt_plot_marker.cpp
new file mode 100644
index 0000000..900f145
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_marker.cpp
@@ -0,0 +1,608 @@
+/* -*- 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_plot_marker.h"
+#include "qwt_painter.h"
+#include "qwt_scale_map.h"
+#include "qwt_symbol.h"
+#include "qwt_text.h"
+#include "qwt_math.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include <qpainter.h>
+
+class QwtPlotMarker::PrivateData
+{
+public:
+ PrivateData():
+ labelAlignment( Qt::AlignCenter ),
+ labelOrientation( Qt::Horizontal ),
+ spacing( 2 ),
+ symbol( NULL ),
+ style( QwtPlotMarker::NoLine ),
+ xValue( 0.0 ),
+ yValue( 0.0 )
+ {
+ }
+
+ ~PrivateData()
+ {
+ delete symbol;
+ }
+
+ QwtText label;
+ Qt::Alignment labelAlignment;
+ Qt::Orientation labelOrientation;
+ int spacing;
+
+ QPen pen;
+ const QwtSymbol *symbol;
+ LineStyle style;
+
+ double xValue;
+ double yValue;
+};
+
+//! Sets alignment to Qt::AlignCenter, and style to QwtPlotMarker::NoLine
+QwtPlotMarker::QwtPlotMarker():
+ QwtPlotItem( QwtText( "Marker" ) )
+{
+ d_data = new PrivateData;
+ setZ( 30.0 );
+}
+
+//! Destructor
+QwtPlotMarker::~QwtPlotMarker()
+{
+ delete d_data;
+}
+
+//! \return QwtPlotItem::Rtti_PlotMarker
+int QwtPlotMarker::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotMarker;
+}
+
+//! Return Value
+QPointF QwtPlotMarker::value() const
+{
+ return QPointF( d_data->xValue, d_data->yValue );
+}
+
+//! Return x Value
+double QwtPlotMarker::xValue() const
+{
+ return d_data->xValue;
+}
+
+//! Return y Value
+double QwtPlotMarker::yValue() const
+{
+ return d_data->yValue;
+}
+
+//! Set Value
+void QwtPlotMarker::setValue( const QPointF& pos )
+{
+ setValue( pos.x(), pos.y() );
+}
+
+//! Set Value
+void QwtPlotMarker::setValue( double x, double y )
+{
+ if ( x != d_data->xValue || y != d_data->yValue )
+ {
+ d_data->xValue = x;
+ d_data->yValue = y;
+ itemChanged();
+ }
+}
+
+//! Set X Value
+void QwtPlotMarker::setXValue( double x )
+{
+ setValue( x, d_data->yValue );
+}
+
+//! Set Y Value
+void QwtPlotMarker::setYValue( double y )
+{
+ setValue( d_data->xValue, y );
+}
+
+/*!
+ Draw the marker
+
+ \param painter Painter
+ \param xMap x Scale Map
+ \param yMap y Scale Map
+ \param canvasRect Contents rect of the canvas in painter coordinates
+*/
+void QwtPlotMarker::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ const QPointF pos( xMap.transform( d_data->xValue ),
+ yMap.transform( d_data->yValue ) );
+
+ // draw lines
+
+ drawLines( painter, canvasRect, pos );
+
+ // draw symbol
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
+ {
+ const QSizeF sz = d_data->symbol->size();
+
+ const QRectF clipRect = canvasRect.adjusted(
+ -sz.width(), -sz.height(), sz.width(), sz.height() );
+
+ if ( clipRect.contains( pos ) )
+ d_data->symbol->drawSymbol( painter, pos );
+ }
+
+ drawLabel( painter, canvasRect, pos );
+}
+
+/*!
+ Draw the lines marker
+
+ \param painter Painter
+ \param canvasRect Contents rect of the canvas in painter coordinates
+ \param pos Position of the marker, translated into widget coordinates
+
+ \sa drawLabel(), QwtSymbol::drawSymbol()
+*/
+void QwtPlotMarker::drawLines( QPainter *painter,
+ const QRectF &canvasRect, const QPointF &pos ) const
+{
+ if ( d_data->style == NoLine )
+ return;
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ painter->setPen( d_data->pen );
+ if ( d_data->style == QwtPlotMarker::HLine ||
+ d_data->style == QwtPlotMarker::Cross )
+ {
+ double y = pos.y();
+ if ( doAlign )
+ y = qRound( y );
+
+ QwtPainter::drawLine( painter, canvasRect.left(),
+ y, canvasRect.right() - 1.0, y );
+ }
+ if ( d_data->style == QwtPlotMarker::VLine ||
+ d_data->style == QwtPlotMarker::Cross )
+ {
+ double x = pos.x();
+ if ( doAlign )
+ x = qRound( x );
+
+ QwtPainter::drawLine( painter, x,
+ canvasRect.top(), x, canvasRect.bottom() - 1.0 );
+ }
+}
+
+/*!
+ Align and draw the text label of the marker
+
+ \param painter Painter
+ \param canvasRect Contents rect of the canvas in painter coordinates
+ \param pos Position of the marker, translated into widget coordinates
+
+ \sa drawLabel(), QwtSymbol::drawSymbol()
+*/
+void QwtPlotMarker::drawLabel( QPainter *painter,
+ const QRectF &canvasRect, const QPointF &pos ) const
+{
+ if ( d_data->label.isEmpty() )
+ return;
+
+ Qt::Alignment align = d_data->labelAlignment;
+ QPointF alignPos = pos;
+
+ QSizeF symbolOff( 0, 0 );
+
+ switch ( d_data->style )
+ {
+ case QwtPlotMarker::VLine:
+ {
+ // In VLine-style the y-position is pointless and
+ // the alignment flags are relative to the canvas
+
+ if ( d_data->labelAlignment & Qt::AlignTop )
+ {
+ alignPos.setY( canvasRect.top() );
+ align &= ~Qt::AlignTop;
+ align |= Qt::AlignBottom;
+ }
+ else if ( d_data->labelAlignment & Qt::AlignBottom )
+ {
+ // In HLine-style the x-position is pointless and
+ // the alignment flags are relative to the canvas
+
+ alignPos.setY( canvasRect.bottom() - 1 );
+ align &= ~Qt::AlignBottom;
+ align |= Qt::AlignTop;
+ }
+ else
+ {
+ alignPos.setY( canvasRect.center().y() );
+ }
+ break;
+ }
+ case QwtPlotMarker::HLine:
+ {
+ if ( d_data->labelAlignment & Qt::AlignLeft )
+ {
+ alignPos.setX( canvasRect.left() );
+ align &= ~Qt::AlignLeft;
+ align |= Qt::AlignRight;
+ }
+ else if ( d_data->labelAlignment & Qt::AlignRight )
+ {
+ alignPos.setX( canvasRect.right() - 1 );
+ align &= ~Qt::AlignRight;
+ align |= Qt::AlignLeft;
+ }
+ else
+ {
+ alignPos.setX( canvasRect.center().x() );
+ }
+ break;
+ }
+ default:
+ {
+ if ( d_data->symbol &&
+ ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
+ {
+ symbolOff = d_data->symbol->size() + QSizeF( 1, 1 );
+ symbolOff /= 2;
+ }
+ }
+ }
+
+ qreal pw2 = d_data->pen.widthF() / 2.0;
+ if ( pw2 == 0.0 )
+ pw2 = 0.5;
+
+ const int spacing = d_data->spacing;
+
+ const qreal xOff = qMax( pw2, symbolOff.width() );
+ const qreal yOff = qMax( pw2, symbolOff.height() );
+
+ const QSizeF textSize = d_data->label.textSize( painter->font() );
+
+ if ( align & Qt::AlignLeft )
+ {
+ alignPos.rx() -= xOff + spacing;
+ if ( d_data->labelOrientation == Qt::Vertical )
+ alignPos.rx() -= textSize.height();
+ else
+ alignPos.rx() -= textSize.width();
+ }
+ else if ( align & Qt::AlignRight )
+ {
+ alignPos.rx() += xOff + spacing;
+ }
+ else
+ {
+ if ( d_data->labelOrientation == Qt::Vertical )
+ alignPos.rx() -= textSize.height() / 2;
+ else
+ alignPos.rx() -= textSize.width() / 2;
+ }
+
+ if ( align & Qt::AlignTop )
+ {
+ alignPos.ry() -= yOff + spacing;
+ if ( d_data->labelOrientation != Qt::Vertical )
+ alignPos.ry() -= textSize.height();
+ }
+ else if ( align & Qt::AlignBottom )
+ {
+ alignPos.ry() += yOff + spacing;
+ if ( d_data->labelOrientation == Qt::Vertical )
+ alignPos.ry() += textSize.width();
+ }
+ else
+ {
+ if ( d_data->labelOrientation == Qt::Vertical )
+ alignPos.ry() += textSize.width() / 2;
+ else
+ alignPos.ry() -= textSize.height() / 2;
+ }
+
+ painter->translate( alignPos.x(), alignPos.y() );
+ if ( d_data->labelOrientation == Qt::Vertical )
+ painter->rotate( -90.0 );
+
+ const QRectF textRect( 0, 0, textSize.width(), textSize.height() );
+ d_data->label.draw( painter, textRect );
+}
+
+/*!
+ \brief Set the line style
+ \param style Line style.
+ \sa lineStyle()
+*/
+void QwtPlotMarker::setLineStyle( LineStyle style )
+{
+ if ( style != d_data->style )
+ {
+ d_data->style = style;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the line style
+ \sa setLineStyle()
+*/
+QwtPlotMarker::LineStyle QwtPlotMarker::lineStyle() const
+{
+ return d_data->style;
+}
+
+/*!
+ \brief Assign a symbol
+ \param symbol New symbol
+ \sa symbol()
+*/
+void QwtPlotMarker::setSymbol( const QwtSymbol *symbol )
+{
+ if ( symbol != d_data->symbol )
+ {
+ delete d_data->symbol;
+ d_data->symbol = symbol;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the symbol
+ \sa setSymbol(), QwtSymbol
+*/
+const QwtSymbol *QwtPlotMarker::symbol() const
+{
+ return d_data->symbol;
+}
+
+/*!
+ \brief Set the label
+ \param label label text
+ \sa label()
+*/
+void QwtPlotMarker::setLabel( const QwtText& label )
+{
+ if ( label != d_data->label )
+ {
+ d_data->label = label;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the label
+ \sa setLabel()
+*/
+QwtText QwtPlotMarker::label() const
+{
+ return d_data->label;
+}
+
+/*!
+ \brief Set the alignment of the label
+
+ In case of QwtPlotMarker::HLine the alignment is relative to the
+ y position of the marker, but the horizontal flags correspond to the
+ canvas rectangle. In case of QwtPlotMarker::VLine the alignment is
+ relative to the x position of the marker, but the vertical flags
+ correspond to the canvas rectangle.
+
+ In all other styles the alignment is relative to the marker's position.
+
+ \param align Alignment.
+ \sa labelAlignment(), labelOrientation()
+*/
+void QwtPlotMarker::setLabelAlignment( Qt::Alignment align )
+{
+ if ( align != d_data->labelAlignment )
+ {
+ d_data->labelAlignment = align;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the label alignment
+ \sa setLabelAlignment(), setLabelOrientation()
+*/
+Qt::Alignment QwtPlotMarker::labelAlignment() const
+{
+ return d_data->labelAlignment;
+}
+
+/*!
+ \brief Set the orientation of the label
+
+ When orientation is Qt::Vertical the label is rotated by 90.0 degrees
+ ( from bottom to top ).
+
+ \param orientation Orientation of the label
+
+ \sa labelOrientation(), setLabelAlignment()
+*/
+void QwtPlotMarker::setLabelOrientation( Qt::Orientation orientation )
+{
+ if ( orientation != d_data->labelOrientation )
+ {
+ d_data->labelOrientation = orientation;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the label orientation
+ \sa setLabelOrientation(), labelAlignment()
+*/
+Qt::Orientation QwtPlotMarker::labelOrientation() const
+{
+ return d_data->labelOrientation;
+}
+
+/*!
+ \brief Set the spacing
+
+ When the label is not centered on the marker position, the spacing
+ is the distance between the position and the label.
+
+ \param spacing Spacing
+ \sa spacing(), setLabelAlignment()
+*/
+void QwtPlotMarker::setSpacing( int spacing )
+{
+ if ( spacing < 0 )
+ spacing = 0;
+
+ if ( spacing == d_data->spacing )
+ return;
+
+ d_data->spacing = spacing;
+ itemChanged();
+}
+
+/*!
+ \return the spacing
+ \sa setSpacing()
+*/
+int QwtPlotMarker::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ Specify a pen for the line.
+
+ \param pen New pen
+ \sa linePen()
+*/
+void QwtPlotMarker::setLinePen( const QPen &pen )
+{
+ if ( pen != d_data->pen )
+ {
+ d_data->pen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \return the line pen
+ \sa setLinePen()
+*/
+const QPen &QwtPlotMarker::linePen() const
+{
+ return d_data->pen;
+}
+
+QRectF QwtPlotMarker::boundingRect() const
+{
+ return QRectF( d_data->xValue, d_data->yValue, 0.0, 0.0 );
+}
+
+/*!
+ \brief Update the widget that represents the item on the legend
+
+ \param legend Legend
+ \sa drawLegendIdentifier(), legendItem(), itemChanged(), QwtLegend()
+
+ \note In the default setting QwtPlotItem::Legend is disabled
+*/
+void QwtPlotMarker::updateLegend( QwtLegend *legend ) const
+{
+ if ( legend && testItemAttribute( QwtPlotItem::Legend )
+ && d_data->symbol && d_data->symbol->style() != QwtSymbol::NoSymbol )
+ {
+ QWidget *lgdItem = legend->find( this );
+ if ( lgdItem == NULL )
+ {
+ lgdItem = legendItem();
+ if ( lgdItem )
+ legend->insert( this, lgdItem );
+ }
+
+ QwtLegendItem *l = qobject_cast<QwtLegendItem *>( lgdItem );
+ if ( l )
+ l->setIdentifierSize( d_data->symbol->boundingSize() );
+ }
+
+ QwtPlotItem::updateLegend( legend );
+}
+
+/*!
+ \brief Draw the identifier representing the marker on the legend
+
+ \param painter Painter
+ \param rect Bounding rectangle for the identifier
+
+ \sa updateLegend(), QwtPlotItem::Legend
+*/
+void QwtPlotMarker::drawLegendIdentifier(
+ QPainter *painter, const QRectF &rect ) const
+{
+ if ( rect.isEmpty() )
+ return;
+
+ painter->save();
+ painter->setClipRect( rect, Qt::IntersectClip );
+
+ if ( d_data->style != QwtPlotMarker::NoLine )
+ {
+ painter->setPen( d_data->pen );
+
+ if ( d_data->style == QwtPlotMarker::HLine ||
+ d_data->style == QwtPlotMarker::Cross )
+ {
+ QwtPainter::drawLine( painter, rect.left(), rect.center().y(),
+ rect.right(), rect.center().y() );
+ }
+
+ if ( d_data->style == QwtPlotMarker::VLine ||
+ d_data->style == QwtPlotMarker::Cross )
+ {
+ QwtPainter::drawLine( painter, rect.center().x(), rect.top(),
+ rect.center().x(), rect.bottom() );
+ }
+ }
+
+ if ( d_data->symbol && d_data->symbol->style() != QwtSymbol::NoSymbol )
+ {
+ QSize symbolSize = d_data->symbol->boundingSize();
+ symbolSize -= QSize( 2, 2 );
+
+ // scale the symbol size down if it doesn't fit into rect.
+
+ double xRatio = 1.0;
+ if ( rect.width() < symbolSize.width() )
+ xRatio = rect.width() / symbolSize.width();
+ double yRatio = 1.0;
+ if ( rect.height() < symbolSize.height() )
+ yRatio = rect.height() / symbolSize.height();
+
+ const double ratio = qMin( xRatio, yRatio );
+
+ painter->scale( ratio, ratio );
+ d_data->symbol->drawSymbol( painter, rect.center() / ratio );
+ }
+
+ painter->restore();
+}
+
diff --git a/src/libpcp_qwt/src/qwt_plot_marker.h b/src/libpcp_qwt/src/qwt_plot_marker.h
new file mode 100644
index 0000000..63a0d1d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_marker.h
@@ -0,0 +1,124 @@
+/* -*- 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_PLOT_MARKER_H
+#define QWT_PLOT_MARKER_H
+
+#include <qpen.h>
+#include <qfont.h>
+#include <qstring.h>
+#include <qbrush.h>
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+
+class QRectF;
+class QwtText;
+class QwtSymbol;
+
+/*!
+ \brief A class for drawing markers
+
+ A marker can be a horizontal line, a vertical line,
+ a symbol, a label or any combination of them, which can
+ be drawn around a center point inside a bounding rectangle.
+
+ The QwtPlotMarker::setSymbol() member assigns a symbol to the marker.
+ The symbol is drawn at the specified point.
+
+ With setLabel(), a label can be assigned to the marker.
+ The setLabelAlignment() member specifies where the label is
+ drawn. All the Align*-constants in Qt::AlignmentFlags (see Qt documentation)
+ are valid. The interpretation of the alignment depends on the marker's
+ line style. The alignment refers to the center point of
+ the marker, which means, for example, that the label would be printed
+ left above the center point if the alignment was set to
+ Qt::AlignLeft | Qt::AlignTop.
+*/
+
+class QWT_EXPORT QwtPlotMarker: public QwtPlotItem
+{
+public:
+
+ /*!
+ Line styles.
+ \sa setLineStyle(), lineStyle()
+ */
+ enum LineStyle
+ {
+ //! No line
+ NoLine,
+
+ //! A horizontal line
+ HLine,
+
+ //! A vertical line
+ VLine,
+
+ //! A crosshair
+ Cross
+ };
+
+ explicit QwtPlotMarker();
+ virtual ~QwtPlotMarker();
+
+ virtual int rtti() const;
+
+ double xValue() const;
+ double yValue() const;
+ QPointF value() const;
+
+ void setXValue( double );
+ void setYValue( double );
+ void setValue( double, double );
+ void setValue( const QPointF & );
+
+ void setLineStyle( LineStyle st );
+ LineStyle lineStyle() const;
+
+ void setLinePen( const QPen &p );
+ const QPen &linePen() const;
+
+ void setSymbol( const QwtSymbol * );
+ const QwtSymbol *symbol() const;
+
+ void setLabel( const QwtText& );
+ QwtText label() const;
+
+ void setLabelAlignment( Qt::Alignment );
+ Qt::Alignment labelAlignment() const;
+
+ void setLabelOrientation( Qt::Orientation );
+ Qt::Orientation labelOrientation() const;
+
+ void setSpacing( int );
+ int spacing() const;
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF & ) const;
+
+ virtual QRectF boundingRect() const;
+
+ virtual void updateLegend( QwtLegend * ) const;
+ virtual void drawLegendIdentifier( QPainter *, const QRectF & ) const;
+
+protected:
+ virtual void drawLines( QPainter *,
+ const QRectF &, const QPointF & ) const;
+
+ virtual void drawLabel( QPainter *,
+ const QRectF &, const QPointF & ) const;
+
+private:
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_panner.cpp b/src/libpcp_qwt/src/qwt_plot_panner.cpp
new file mode 100644
index 0000000..fa8cb54
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_panner.cpp
@@ -0,0 +1,175 @@
+/* -*- 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_plot_panner.h"
+#include "qwt_scale_div.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+
+class QwtPlotPanner::PrivateData
+{
+public:
+ PrivateData()
+ {
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ isAxisEnabled[axis] = true;
+ }
+
+ bool isAxisEnabled[QwtPlot::axisCnt];
+};
+
+/*!
+ \brief Create a plot panner
+
+ The panner is enabled for all axes
+
+ \param canvas Plot canvas to pan, also the parent object
+
+ \sa setAxisEnabled()
+*/
+QwtPlotPanner::QwtPlotPanner( QwtPlotCanvas *canvas ):
+ QwtPanner( canvas )
+{
+ d_data = new PrivateData();
+
+ connect( this, SIGNAL( panned( int, int ) ),
+ SLOT( moveCanvas( int, int ) ) );
+}
+
+//! Destructor
+QwtPlotPanner::~QwtPlotPanner()
+{
+ delete d_data;
+}
+
+/*!
+ \brief En/Disable an axis
+
+ Axes that are enabled will be synchronized to the
+ result of panning. All other axes will remain unchanged.
+
+ \param axis Axis, see QwtPlot::Axis
+ \param on On/Off
+
+ \sa isAxisEnabled(), moveCanvas()
+*/
+void QwtPlotPanner::setAxisEnabled( int axis, bool on )
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->isAxisEnabled[axis] = on;
+}
+
+/*!
+ Test if an axis is enabled
+
+ \param axis Axis, see QwtPlot::Axis
+ \return True, if the axis is enabled
+
+ \sa setAxisEnabled(), moveCanvas()
+*/
+bool QwtPlotPanner::isAxisEnabled( int axis ) const
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ return d_data->isAxisEnabled[axis];
+
+ return true;
+}
+
+//! Return observed plot canvas
+QwtPlotCanvas *QwtPlotPanner::canvas()
+{
+ return qobject_cast<QwtPlotCanvas *>( parentWidget() );
+}
+
+//! Return Observed plot canvas
+const QwtPlotCanvas *QwtPlotPanner::canvas() const
+{
+ return qobject_cast<const QwtPlotCanvas *>( parentWidget() );
+}
+
+//! Return plot widget, containing the observed plot canvas
+QwtPlot *QwtPlotPanner::plot()
+{
+ QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+//! Return plot widget, containing the observed plot canvas
+const QwtPlot *QwtPlotPanner::plot() const
+{
+ const QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+/*!
+ Adjust the enabled axes according to dx/dy
+
+ \param dx Pixel offset in x direction
+ \param dy Pixel offset in y direction
+
+ \sa QwtPanner::panned()
+*/
+void QwtPlotPanner::moveCanvas( int dx, int dy )
+{
+ if ( dx == 0 && dy == 0 )
+ return;
+
+ QwtPlot *plot = this->plot();
+ if ( plot == NULL )
+ return;
+
+ const bool doAutoReplot = plot->autoReplot();
+ plot->setAutoReplot( false );
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( !d_data->isAxisEnabled[axis] )
+ continue;
+
+ const QwtScaleMap map = plot->canvasMap( axis );
+
+ const double p1 = map.transform( plot->axisScaleDiv( axis )->lowerBound() );
+ const double p2 = map.transform( plot->axisScaleDiv( axis )->upperBound() );
+
+ double d1, d2;
+ if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
+ {
+ d1 = map.invTransform( p1 - dx );
+ d2 = map.invTransform( p2 - dx );
+ }
+ else
+ {
+ d1 = map.invTransform( p1 - dy );
+ d2 = map.invTransform( p2 - dy );
+ }
+
+ plot->setAxisScale( axis, d1, d2 );
+ }
+
+ plot->setAutoReplot( doAutoReplot );
+ plot->replot();
+}
+
+/*!
+ Calculate a mask from the border mask of the canvas
+ \sa QwtPlotCanvas::borderMask()
+*/
+QBitmap QwtPlotPanner::contentsMask() const
+{
+ if ( canvas() )
+ return canvas()->borderMask( size() );
+
+ return QwtPanner::contentsMask();
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_panner.h b/src/libpcp_qwt/src/qwt_plot_panner.h
new file mode 100644
index 0000000..fc783e3
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_panner.h
@@ -0,0 +1,60 @@
+/* -*- 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_PLOT_PANNER_H
+#define QWT_PLOT_PANNER_H 1
+
+#include "qwt_global.h"
+#include "qwt_panner.h"
+
+class QwtPlotCanvas;
+class QwtPlot;
+
+/*!
+ \brief QwtPlotPanner provides panning of a plot canvas
+
+ QwtPlotPanner is a panner for a QwtPlotCanvas, that
+ adjusts the scales of the axes after dropping
+ the canvas on its new position.
+
+ Together with QwtPlotZoomer and QwtPlotMagnifier powerful ways
+ of navigating on a QwtPlot widget can be implemented easily.
+
+ \note The axes are not updated, while dragging the canvas
+ \sa QwtPlotZoomer, QwtPlotMagnifier
+*/
+class QWT_EXPORT QwtPlotPanner: public QwtPanner
+{
+ Q_OBJECT
+
+public:
+ explicit QwtPlotPanner( QwtPlotCanvas * );
+ virtual ~QwtPlotPanner();
+
+ QwtPlotCanvas *canvas();
+ const QwtPlotCanvas *canvas() const;
+
+ QwtPlot *plot();
+ const QwtPlot *plot() const;
+
+ void setAxisEnabled( int axis, bool on );
+ bool isAxisEnabled( int axis ) const;
+
+protected Q_SLOTS:
+ virtual void moveCanvas( int dx, int dy );
+
+protected:
+ virtual QBitmap contentsMask() const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_picker.cpp b/src/libpcp_qwt/src/qwt_plot_picker.cpp
new file mode 100644
index 0000000..7a4073c
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_picker.cpp
@@ -0,0 +1,383 @@
+/* -*- 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_plot_picker.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_div.h"
+#include "qwt_painter.h"
+#include "qwt_scale_map.h"
+#include "qwt_picker_machine.h"
+
+/*!
+ \brief Create a plot picker
+
+ The picker is set to those x- and y-axis of the plot
+ that are enabled. If both or no x-axis are enabled, the picker
+ is set to QwtPlot::xBottom. If both or no y-axis are
+ enabled, it is set to QwtPlot::yLeft.
+
+ \param canvas Plot canvas to observe, also the parent object
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
+*/
+
+QwtPlotPicker::QwtPlotPicker( QwtPlotCanvas *canvas ):
+ QwtPicker( canvas ),
+ d_xAxis( -1 ),
+ d_yAxis( -1 )
+{
+ if ( !canvas )
+ return;
+
+ // attach axes
+
+ int xAxis = QwtPlot::xBottom;
+
+ const QwtPlot *plot = QwtPlotPicker::plot();
+ if ( !plot->axisEnabled( QwtPlot::xBottom ) &&
+ plot->axisEnabled( QwtPlot::xTop ) )
+ {
+ xAxis = QwtPlot::xTop;
+ }
+
+ int yAxis = QwtPlot::yLeft;
+ if ( !plot->axisEnabled( QwtPlot::yLeft ) &&
+ plot->axisEnabled( QwtPlot::yRight ) )
+ {
+ yAxis = QwtPlot::yRight;
+ }
+
+ setAxis( xAxis, yAxis );
+}
+
+/*!
+ Create a plot picker
+
+ \param xAxis Set the x axis of the picker
+ \param yAxis Set the y axis of the picker
+ \param canvas Plot canvas to observe, also the parent object
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
+*/
+QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis, QwtPlotCanvas *canvas ):
+ QwtPicker( canvas ),
+ d_xAxis( xAxis ),
+ d_yAxis( yAxis )
+{
+}
+
+/*!
+ Create a plot picker
+
+ \param xAxis X axis of the picker
+ \param yAxis Y axis of the picker
+ \param rubberBand Rubberband style
+ \param trackerMode Tracker mode
+ \param canvas Plot canvas to observe, also the parent object
+
+ \sa QwtPicker, QwtPicker::setSelectionFlags(), QwtPicker::setRubberBand(),
+ QwtPicker::setTrackerMode
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
+*/
+QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis,
+ RubberBand rubberBand, DisplayMode trackerMode,
+ QwtPlotCanvas *canvas ):
+ QwtPicker( rubberBand, trackerMode, canvas ),
+ d_xAxis( xAxis ),
+ d_yAxis( yAxis )
+{
+}
+
+//! Destructor
+QwtPlotPicker::~QwtPlotPicker()
+{
+}
+
+//! Return observed plot canvas
+QwtPlotCanvas *QwtPlotPicker::canvas()
+{
+ return qobject_cast<QwtPlotCanvas *>( parentWidget() );
+}
+
+//! Return Observed plot canvas
+const QwtPlotCanvas *QwtPlotPicker::canvas() const
+{
+ return qobject_cast<const QwtPlotCanvas *>( parentWidget() );
+}
+
+//! Return plot widget, containing the observed plot canvas
+QwtPlot *QwtPlotPicker::plot()
+{
+ QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+//! Return plot widget, containing the observed plot canvas
+const QwtPlot *QwtPlotPicker::plot() const
+{
+ const QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+/*!
+ Return normalized bounding rect of the axes
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot().
+*/
+QRectF QwtPlotPicker::scaleRect() const
+{
+ QRectF rect;
+
+ if ( plot() )
+ {
+ const QwtScaleDiv *xs = plot()->axisScaleDiv( xAxis() );
+ const QwtScaleDiv *ys = plot()->axisScaleDiv( yAxis() );
+
+ if ( xs && ys )
+ {
+ rect = QRectF( xs->lowerBound(), ys->lowerBound(),
+ xs->range(), ys->range() );
+ rect = rect.normalized();
+ }
+ }
+
+ return rect;
+}
+
+/*!
+ Set the x and y axes of the picker
+
+ \param xAxis X axis
+ \param yAxis Y axis
+*/
+void QwtPlotPicker::setAxis( int xAxis, int yAxis )
+{
+ const QwtPlot *plt = plot();
+ if ( !plt )
+ return;
+
+ if ( xAxis != d_xAxis || yAxis != d_yAxis )
+ {
+ d_xAxis = xAxis;
+ d_yAxis = yAxis;
+ }
+}
+
+//! Return x axis
+int QwtPlotPicker::xAxis() const
+{
+ return d_xAxis;
+}
+
+//! Return y axis
+int QwtPlotPicker::yAxis() const
+{
+ return d_yAxis;
+}
+
+/*!
+ Translate a pixel position into a position string
+
+ \param pos Position in pixel coordinates
+ \return Position string
+*/
+QwtText QwtPlotPicker::trackerText( const QPoint &pos ) const
+{
+ return trackerTextF( invTransform( pos ) );
+}
+
+/*!
+ \brief Translate a position into a position string
+
+ In case of HLineRubberBand the label is the value of the
+ y position, in case of VLineRubberBand the value of the x position.
+ Otherwise the label contains x and y position separated by a ',' .
+
+ The format for the double to string conversion is "%.4f".
+
+ \param pos Position
+ \return Position string
+*/
+QwtText QwtPlotPicker::trackerTextF( const QPointF &pos ) const
+{
+ QString text;
+
+ switch ( rubberBand() )
+ {
+ case HLineRubberBand:
+ text.sprintf( "%.4f", pos.y() );
+ break;
+ case VLineRubberBand:
+ text.sprintf( "%.4f", pos.x() );
+ break;
+ default:
+ text.sprintf( "%.4f, %.4f", pos.x(), pos.y() );
+ }
+ return QwtText( text );
+}
+
+/*!
+ Append a point to the selection and update rubberband and tracker.
+
+ \param pos Additional point
+ \sa isActive, begin(), end(), move(), appended()
+
+ \note The appended(const QPoint &), appended(const QDoublePoint &)
+ signals are emitted.
+*/
+void QwtPlotPicker::append( const QPoint &pos )
+{
+ QwtPicker::append( pos );
+ Q_EMIT appended( invTransform( pos ) );
+}
+
+/*!
+ Move the last point of the selection
+
+ \param pos New position
+ \sa isActive, begin(), end(), append()
+
+ \note The moved(const QPoint &), moved(const QDoublePoint &)
+ signals are emitted.
+*/
+void QwtPlotPicker::move( const QPoint &pos )
+{
+ QwtPicker::move( pos );
+ Q_EMIT moved( invTransform( pos ) );
+}
+
+/*!
+ Close a selection setting the state to inactive.
+
+ \param ok If true, complete the selection and emit selected signals
+ otherwise discard the selection.
+ \return true if the selection is accepted, false otherwise
+*/
+
+bool QwtPlotPicker::end( bool ok )
+{
+ ok = QwtPicker::end( ok );
+ if ( !ok )
+ return false;
+
+ QwtPlot *plot = QwtPlotPicker::plot();
+ if ( !plot )
+ return false;
+
+ const QPolygon points = selection();
+ if ( points.count() == 0 )
+ return false;
+
+ QwtPickerMachine::SelectionType selectionType =
+ QwtPickerMachine::NoSelection;
+
+ if ( stateMachine() )
+ selectionType = stateMachine()->selectionType();
+
+ switch ( selectionType )
+ {
+ case QwtPickerMachine::PointSelection:
+ {
+ const QPointF pos = invTransform( points.first() );
+ Q_EMIT selected( pos );
+ break;
+ }
+ case QwtPickerMachine::RectSelection:
+ {
+ if ( points.count() >= 2 )
+ {
+ const QPoint p1 = points.first();
+ const QPoint p2 = points.last();
+
+ const QRect rect = QRect( p1, p2 ).normalized();
+ Q_EMIT selected( invTransform( rect ) );
+ }
+ break;
+ }
+ case QwtPickerMachine::PolygonSelection:
+ {
+ QVector<QPointF> dpa( points.count() );
+ for ( int i = 0; i < points.count(); i++ )
+ dpa[i] = invTransform( points[i] );
+
+ Q_EMIT selected( dpa );
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/*!
+ Translate a rectangle from pixel into plot coordinates
+
+ \return Rectangle in plot coordinates
+ \sa transform()
+*/
+QRectF QwtPlotPicker::invTransform( const QRect &rect ) const
+{
+ const QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
+ const QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
+
+ return QwtScaleMap::invTransform( xMap, yMap, rect );
+}
+
+/*!
+ Translate a rectangle from plot into pixel coordinates
+ \return Rectangle in pixel coordinates
+ \sa invTransform()
+*/
+QRect QwtPlotPicker::transform( const QRectF &rect ) const
+{
+ const QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
+ const QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
+
+ return QwtScaleMap::transform( xMap, yMap, rect ).toRect();
+}
+
+/*!
+ Translate a point from pixel into plot coordinates
+ \return Point in plot coordinates
+ \sa transform()
+*/
+QPointF QwtPlotPicker::invTransform( const QPoint &pos ) const
+{
+ QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
+ QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
+
+ return QPointF(
+ xMap.invTransform( pos.x() ),
+ yMap.invTransform( pos.y() )
+ );
+}
+
+/*!
+ Translate a point from plot into pixel coordinates
+ \return Point in pixel coordinates
+ \sa invTransform()
+*/
+QPoint QwtPlotPicker::transform( const QPointF &pos ) const
+{
+ QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
+ QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
+
+ const QPointF p( xMap.transform( pos.x() ),
+ yMap.transform( pos.y() ) );
+
+ return p.toPoint();
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_picker.h b/src/libpcp_qwt/src/qwt_plot_picker.h
new file mode 100644
index 0000000..f7d1bee
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_picker.h
@@ -0,0 +1,115 @@
+/* -*- 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_PLOT_PICKER_H
+#define QWT_PLOT_PICKER_H
+
+#include "qwt_global.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_picker.h"
+#include <qvector.h>
+
+class QwtPlot;
+
+/*!
+ \brief QwtPlotPicker provides selections on a plot canvas
+
+ QwtPlotPicker is a QwtPicker tailored for selections on
+ a plot canvas. It is set to a x-Axis and y-Axis and
+ translates all pixel coordinates into this coodinate system.
+*/
+
+class QWT_EXPORT QwtPlotPicker: public QwtPicker
+{
+ Q_OBJECT
+
+public:
+ explicit QwtPlotPicker( QwtPlotCanvas * );
+ virtual ~QwtPlotPicker();
+
+ explicit QwtPlotPicker( int xAxis, int yAxis, QwtPlotCanvas * );
+
+ explicit QwtPlotPicker( int xAxis, int yAxis,
+ RubberBand rubberBand, DisplayMode trackerMode,
+ QwtPlotCanvas * );
+
+ virtual void setAxis( int xAxis, int yAxis );
+
+ int xAxis() const;
+ int yAxis() const;
+
+ QwtPlot *plot();
+ const QwtPlot *plot() const;
+
+ QwtPlotCanvas *canvas();
+ const QwtPlotCanvas *canvas() const;
+
+Q_SIGNALS:
+
+ /*!
+ A signal emitted in case of selectionFlags() & PointSelection.
+ \param pos Selected point
+ */
+ void selected( const QPointF &pos );
+
+ /*!
+ A signal emitted in case of selectionFlags() & RectSelection.
+ \param rect Selected rectangle
+ */
+ void selected( const QRectF &rect );
+
+ /*!
+ A signal emitting the selected points,
+ at the end of a selection.
+
+ \param pa Selected points
+ */
+ void selected( const QVector<QPointF> &pa );
+
+ /*!
+ A signal emitted when a point has been appended to the selection
+
+ \param pos Position of the appended point.
+ \sa append(). moved()
+ */
+ void appended( const QPointF &pos );
+
+ /*!
+ A signal emitted whenever the last appended point of the
+ selection has been moved.
+
+ \param pos Position of the moved last point of the selection.
+ \sa move(), appended()
+ */
+ void moved( const QPointF &pos );
+
+protected:
+ QRectF scaleRect() const;
+
+public:
+ QRectF invTransform( const QRect & ) const;
+ QRect transform( const QRectF & ) const;
+
+ QPointF invTransform( const QPoint & ) const;
+ QPoint transform( const QPointF & ) const;
+
+protected:
+ virtual QwtText trackerText( const QPoint & ) const;
+ virtual QwtText trackerTextF( const QPointF & ) const;
+
+ virtual void move( const QPoint & );
+ virtual void append( const QPoint & );
+ virtual bool end( bool ok = true );
+
+private:
+ int d_xAxis;
+ int d_yAxis;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_rasteritem.cpp b/src/libpcp_qwt/src/qwt_plot_rasteritem.cpp
new file mode 100644
index 0000000..08e02e7
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_rasteritem.cpp
@@ -0,0 +1,904 @@
+/* -*- 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_plot_rasteritem.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_scale_map.h"
+#include "qwt_painter.h"
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qpainter.h>
+#include <qpaintengine.h>
+#include <float.h>
+
+class QwtPlotRasterItem::PrivateData
+{
+public:
+ PrivateData():
+ alpha( -1 ),
+ paintAttributes( QwtPlotRasterItem::PaintInDeviceResolution )
+ {
+ cache.policy = QwtPlotRasterItem::NoCache;
+ }
+
+ int alpha;
+ QwtPlotRasterItem::PaintAttributes paintAttributes;
+
+ struct ImageCache
+ {
+ QwtPlotRasterItem::CachePolicy policy;
+ QRectF area;
+ QSizeF size;
+ QImage image;
+ } cache;
+};
+
+
+static QRectF qwtAlignRect(const QRectF &rect)
+{
+ QRectF r;
+ r.setLeft( qRound( rect.left() ) );
+ r.setRight( qRound( rect.right() ) );
+ r.setTop( qRound( rect.top() ) );
+ r.setBottom( qRound( rect.bottom() ) );
+
+ return r;
+}
+
+static QRectF qwtStripRect(const QRectF &rect, const QRectF &area,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QwtInterval &xInterval, const QwtInterval &yInterval)
+{
+ QRectF r = rect;
+ if ( xInterval.borderFlags() & QwtInterval::ExcludeMinimum )
+ {
+ if ( area.left() <= xInterval.minValue() )
+ {
+ if ( xMap.isInverting() )
+ r.adjust(0, 0, -1, 0);
+ else
+ r.adjust(1, 0, 0, 0);
+ }
+ }
+
+ if ( xInterval.borderFlags() & QwtInterval::ExcludeMaximum )
+ {
+ if ( area.right() >= xInterval.maxValue() )
+ {
+ if ( xMap.isInverting() )
+ r.adjust(1, 0, 0, 0);
+ else
+ r.adjust(0, 0, -1, 0);
+ }
+ }
+
+ if ( yInterval.borderFlags() & QwtInterval::ExcludeMinimum )
+ {
+ if ( area.top() <= yInterval.minValue() )
+ {
+ if ( yMap.isInverting() )
+ r.adjust(0, 0, 0, -1);
+ else
+ r.adjust(0, 1, 0, 0);
+ }
+ }
+
+ if ( yInterval.borderFlags() & QwtInterval::ExcludeMaximum )
+ {
+ if ( area.bottom() >= yInterval.maxValue() )
+ {
+ if ( yMap.isInverting() )
+ r.adjust(0, 1, 0, 0);
+ else
+ r.adjust(0, 0, 0, -1);
+ }
+ }
+
+ return r;
+}
+
+static QImage qwtExpandImage(const QImage &image,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &area, const QRectF &area2, const QRectF &paintRect,
+ const QwtInterval &xInterval, const QwtInterval &yInterval )
+{
+ const QRectF strippedRect = qwtStripRect(paintRect, area2,
+ xMap, yMap, xInterval, yInterval);
+ const QSize sz = strippedRect.toRect().size();
+
+ const int w = image.width();
+ const int h = image.height();
+
+ const QRectF r = QwtScaleMap::transform(xMap, yMap, area).normalized();
+ const double pw = ( r.width() - 1) / w;
+ const double ph = ( r.height() - 1) / h;
+
+ double px0, py0;
+ if ( !xMap.isInverting() )
+ {
+ px0 = xMap.transform( area2.left() );
+ px0 = qRound( px0 );
+ px0 = px0 - xMap.transform( area.left() );
+ }
+ else
+ {
+ px0 = xMap.transform( area2.right() );
+ px0 = qRound( px0 );
+ px0 -= xMap.transform( area.right() );
+
+ px0 -= 1.0;
+ }
+ px0 += strippedRect.left() - paintRect.left();
+
+ if ( !yMap.isInverting() )
+ {
+ py0 = yMap.transform( area2.top() );
+ py0 = qRound( py0 );
+ py0 -= yMap.transform( area.top() );
+ }
+ else
+ {
+ py0 = yMap.transform( area2.bottom() );
+ py0 = qRound( py0 );
+ py0 -= yMap.transform( area.bottom() );
+
+ py0 -= 1.0;
+ }
+ py0 += strippedRect.top() - paintRect.top();
+
+ QImage expanded(sz, image.format());
+
+ switch( image.depth() )
+ {
+ case 32:
+ {
+ for ( int y1 = 0; y1 < h; y1++ )
+ {
+ int yy1;
+ if ( y1 == 0 )
+ {
+ yy1 = 0;
+ }
+ else
+ {
+ yy1 = qRound( y1 * ph - py0 );
+ if ( yy1 < 0 )
+ yy1 = 0;
+ }
+
+ int yy2;
+ if ( y1 == h - 1 )
+ {
+ yy2 = sz.height();
+ }
+ else
+ {
+ yy2 = qRound( ( y1 + 1 ) * ph - py0 );
+ if ( yy2 > sz.height() )
+ yy2 = sz.height();
+ }
+
+ const quint32 *line1 = (const quint32 *) image.scanLine( y1 );
+
+ for ( int x1 = 0; x1 < w; x1++ )
+ {
+ int xx1;
+ if ( x1 == 0 )
+ {
+ xx1 = 0;
+ }
+ else
+ {
+ xx1 = qRound( x1 * pw - px0 );
+ if ( xx1 < 0 )
+ xx1 = 0;
+ }
+
+ int xx2;
+ if ( x1 == w - 1 )
+ {
+ xx2 = sz.width();
+ }
+ else
+ {
+ xx2 = qRound( ( x1 + 1 ) * pw - px0 );
+ if ( xx2 > sz.width() )
+ xx2 = sz.width();
+ }
+
+ const quint32 rgb( line1[x1] );
+ for ( int y2 = yy1; y2 < yy2; y2++ )
+ {
+ quint32 *line2 = ( quint32 *) expanded.scanLine( y2 );
+ for ( int x2 = xx1; x2 < xx2; x2++ )
+ line2[x2] = rgb;
+ }
+ }
+ }
+ break;
+ }
+ case 8:
+ {
+ for ( int y1 = 0; y1 < h; y1++ )
+ {
+ int yy1;
+ if ( y1 == 0 )
+ {
+ yy1 = 0;
+ }
+ else
+ {
+ yy1 = qRound( y1 * ph - py0 );
+ if ( yy1 < 0 )
+ yy1 = 0;
+ }
+
+ int yy2;
+ if ( y1 == h - 1 )
+ {
+ yy2 = sz.height();
+ }
+ else
+ {
+ yy2 = qRound( ( y1 + 1 ) * ph - py0 );
+ if ( yy2 > sz.height() )
+ yy2 = sz.height();
+ }
+
+ const uchar *line1 = image.scanLine( y1 );
+
+ for ( int x1 = 0; x1 < w; x1++ )
+ {
+ int xx1;
+ if ( x1 == 0 )
+ {
+ xx1 = 0;
+ }
+ else
+ {
+ xx1 = qRound( x1 * pw - px0 );
+ if ( xx1 < 0 )
+ xx1 = 0;
+ }
+
+ int xx2;
+ if ( x1 == w - 1 )
+ {
+ xx2 = sz.width();
+ }
+ else
+ {
+ xx2 = qRound( ( x1 + 1 ) * pw - px0 );
+ if ( xx2 > sz.width() )
+ xx2 = sz.width();
+ }
+
+ for ( int y2 = yy1; y2 < yy2; y2++ )
+ {
+ uchar *line2 = expanded.scanLine( y2 );
+ memset( line2 + xx1, line1[x1], xx2 - xx1 );
+ }
+ }
+ }
+ break;
+ }
+ default:
+ expanded = image;
+ }
+
+ return expanded;
+}
+
+static QRectF expandToPixels(const QRectF &rect, const QRectF &pixelRect)
+{
+ const double pw = pixelRect.width();
+ const double ph = pixelRect.height();
+
+ const double dx1 = pixelRect.left() - rect.left();
+ const double dx2 = pixelRect.right() - rect.right();
+ const double dy1 = pixelRect.top() - rect.top();
+ const double dy2 = pixelRect.bottom() - rect.bottom();
+
+ QRectF r;
+ r.setLeft( pixelRect.left() - qCeil( dx1 / pw ) * pw );
+ r.setTop( pixelRect.top() - qCeil( dy1 / ph ) * ph );
+ r.setRight( pixelRect.right() - qFloor( dx2 / pw ) * pw );
+ r.setBottom( pixelRect.bottom() - qFloor( dy2 / ph ) * ph );
+
+ return r;
+}
+
+static void transformMaps( const QTransform &tr,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ QwtScaleMap &xxMap, QwtScaleMap &yyMap )
+{
+ const QPointF p1 = tr.map( QPointF( xMap.p1(), yMap.p1() ) );
+ const QPointF p2 = tr.map( QPointF( xMap.p2(), yMap.p2() ) );
+
+ xxMap = xMap;
+ xxMap.setPaintInterval( p1.x(), p2.x() );
+
+ yyMap = yMap;
+ yyMap.setPaintInterval( p1.y(), p2.y() );
+}
+
+static void adjustMaps( QwtScaleMap &xMap, QwtScaleMap &yMap,
+ const QRectF &area, const QRectF &paintRect)
+{
+ double sx1 = area.left();
+ double sx2 = area.right();
+ if ( xMap.isInverting() )
+ qSwap(sx1, sx2);
+
+ double sy1 = area.top();
+ double sy2 = area.bottom();
+
+ if ( yMap.isInverting() )
+ qSwap(sy1, sy2);
+
+ xMap.setPaintInterval(paintRect.left(), paintRect.right());
+ xMap.setScaleInterval(sx1, sx2);
+
+ yMap.setPaintInterval(paintRect.top(), paintRect.bottom());
+ yMap.setScaleInterval(sy1, sy2);
+}
+
+static bool useCache( QwtPlotRasterItem::CachePolicy policy,
+ const QPainter *painter )
+{
+ bool doCache = false;
+
+ if ( policy == QwtPlotRasterItem::PaintCache )
+ {
+ // Caching doesn't make sense, when the item is
+ // not painted to screen
+
+ switch ( painter->paintEngine()->type() )
+ {
+ case QPaintEngine::SVG:
+ case QPaintEngine::Pdf:
+ case QPaintEngine::PostScript:
+ case QPaintEngine::MacPrinter:
+ case QPaintEngine::Picture:
+ break;
+ default:;
+ doCache = true;
+ }
+ }
+
+ return doCache;
+}
+
+static QImage toRgba( const QImage& image, int alpha )
+{
+ if ( alpha < 0 || alpha >= 255 )
+ return image;
+
+ QImage alphaImage( image.size(), QImage::Format_ARGB32 );
+
+ const QRgb mask1 = qRgba( 0, 0, 0, alpha );
+ const QRgb mask2 = qRgba( 255, 255, 255, 0 );
+ const QRgb mask3 = qRgba( 0, 0, 0, 255 );
+
+ const int w = image.size().width();
+ const int h = image.size().height();
+
+ if ( image.depth() == 8 )
+ {
+ for ( int y = 0; y < h; y++ )
+ {
+ QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
+ const unsigned char *line = image.scanLine( y );
+
+ for ( int x = 0; x < w; x++ )
+ *alphaLine++ = ( image.color( *line++ ) & mask2 ) | mask1;
+ }
+ }
+ else if ( image.depth() == 32 )
+ {
+ for ( int y = 0; y < h; y++ )
+ {
+ QRgb* alphaLine = ( QRgb* )alphaImage.scanLine( y );
+ const QRgb* line = ( const QRgb* ) image.scanLine( y );
+
+ for ( int x = 0; x < w; x++ )
+ {
+ const QRgb rgb = *line++;
+ if ( rgb & mask3 ) // alpha != 0
+ *alphaLine++ = ( rgb & mask2 ) | mask1;
+ else
+ *alphaLine++ = rgb;
+ }
+ }
+ }
+
+ return alphaImage;
+}
+
+//! Constructor
+QwtPlotRasterItem::QwtPlotRasterItem( const QString& title ):
+ QwtPlotItem( QwtText( title ) )
+{
+ init();
+}
+
+//! Constructor
+QwtPlotRasterItem::QwtPlotRasterItem( const QwtText& title ):
+ QwtPlotItem( title )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotRasterItem::~QwtPlotRasterItem()
+{
+ delete d_data;
+}
+
+void QwtPlotRasterItem::init()
+{
+ d_data = new PrivateData();
+
+ setItemAttribute( QwtPlotItem::AutoScale, true );
+ setItemAttribute( QwtPlotItem::Legend, false );
+
+ setZ( 8.0 );
+}
+
+/*!
+ Specify an attribute how to draw the raster item
+
+ \param attribute Paint attribute
+ \param on On/Off
+ /sa PaintAttribute, testPaintAttribute()
+*/
+void QwtPlotRasterItem::setPaintAttribute( PaintAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+}
+
+/*!
+ \brief Return the current paint attributes
+ \sa PaintAttribute, setPaintAttribute()
+*/
+bool QwtPlotRasterItem::testPaintAttribute( PaintAttribute attribute ) const
+{
+ return ( d_data->paintAttributes & attribute );
+}
+
+/*!
+ \brief Set an alpha value for the raster data
+
+ Often a plot has several types of raster data organized in layers.
+ ( f.e a geographical map, with weather statistics ).
+ Using setAlpha() raster items can be stacked easily.
+
+ The alpha value is a value [0, 255] to
+ control the transparency of the image. 0 represents a fully
+ transparent color, while 255 represents a fully opaque color.
+
+ \param alpha Alpha value
+
+ - alpha >= 0\n
+ All alpha values of the pixels returned by renderImage() will be set to
+ alpha, beside those with an alpha value of 0 (invalid pixels).
+ - alpha < 0
+ The alpha values returned by renderImage() are not changed.
+
+ The default alpha value is -1.
+
+ \sa alpha()
+*/
+void QwtPlotRasterItem::setAlpha( int alpha )
+{
+ if ( alpha < 0 )
+ alpha = -1;
+
+ if ( alpha > 255 )
+ alpha = 255;
+
+ if ( alpha != d_data->alpha )
+ {
+ d_data->alpha = alpha;
+
+ itemChanged();
+ }
+}
+
+/*!
+ \return Alpha value of the raster item
+ \sa setAlpha()
+*/
+int QwtPlotRasterItem::alpha() const
+{
+ return d_data->alpha;
+}
+
+/*!
+ Change the cache policy
+
+ The default policy is NoCache
+
+ \param policy Cache policy
+ \sa CachePolicy, cachePolicy()
+*/
+void QwtPlotRasterItem::setCachePolicy(
+ QwtPlotRasterItem::CachePolicy policy )
+{
+ if ( d_data->cache.policy != policy )
+ {
+ d_data->cache.policy = policy;
+
+ invalidateCache();
+ itemChanged();
+ }
+}
+
+/*!
+ \return Cache policy
+ \sa CachePolicy, setCachePolicy()
+*/
+QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const
+{
+ return d_data->cache.policy;
+}
+
+/*!
+ Invalidate the paint cache
+ \sa setCachePolicy()
+*/
+void QwtPlotRasterItem::invalidateCache()
+{
+ d_data->cache.image = QImage();
+ d_data->cache.area = QRect();
+ d_data->cache.size = QSize();
+}
+
+/*!
+ \brief Pixel hint
+
+ The geometry of a pixel is used to calculated the resolution and
+ alignment of the rendered image.
+
+ Width and height of the hint need to be the horizontal
+ and vertical distances between 2 neighboured points.
+ The center of the hint has to be the position of any point
+ ( it doesn't matter which one ).
+
+ Limiting the resolution of the image might significantly improve
+ the performance and heavily reduce the amount of memory when rendering
+ a QImage from the raster data.
+
+ The default implementation returns an empty rectangle (QRectF()),
+ meaning, that the image will be rendered in target device ( f.e screen )
+ resolution.
+
+ \param area In most implementations the resolution of the data doesn't
+ depend on the requested area.
+
+ \return Bounding rectangle of a pixel
+
+ \sa render(), renderImage()
+*/
+QRectF QwtPlotRasterItem::pixelHint( const QRectF &area ) const
+{
+ Q_UNUSED( area );
+ return QRectF();
+}
+
+/*!
+ \brief Draw the raster data
+ \param painter Painter
+ \param xMap X-Scale Map
+ \param yMap Y-Scale Map
+ \param canvasRect Contents rect of the plot canvas
+*/
+void QwtPlotRasterItem::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ if ( canvasRect.isEmpty() || d_data->alpha == 0 )
+ return;
+
+ const bool doCache = useCache( d_data->cache.policy, painter );
+
+ const QwtInterval xInterval = interval( Qt::XAxis );
+ const QwtInterval yInterval = interval( Qt::YAxis );
+
+ /*
+ Scaling a rastered image always results in a loss of
+ precision/quality. So we always render the image in
+ paint device resolution.
+ */
+
+ QwtScaleMap xxMap, yyMap;
+ transformMaps( painter->transform(), xMap, yMap, xxMap, yyMap );
+
+ QRectF paintRect = painter->transform().mapRect( canvasRect );
+ QRectF area = QwtScaleMap::invTransform( xxMap, yyMap, paintRect );
+
+ const QRectF br = boundingRect();
+ if ( br.isValid() && !br.contains( area ) )
+ {
+ area &= br;
+ if ( !area.isValid() )
+ return;
+
+ paintRect = QwtScaleMap::transform( xxMap, yyMap, area );
+ }
+
+ QRectF imageRect;
+ QImage image;
+
+ QRectF pixelRect = pixelHint(area);
+ if ( !pixelRect.isEmpty() )
+ {
+ // pixel in target device resolution
+ const double dx = qAbs( xxMap.invTransform( 1 ) - xxMap.invTransform( 0 ) );
+ const double dy = qAbs( yyMap.invTransform( 1 ) - yyMap.invTransform( 0 ) );
+
+ if ( dx > pixelRect.width() && dy > pixelRect.height() )
+ {
+ /*
+ When the resolution of the data pixels is higher than
+ the resolution of the target device we render in
+ target device resolution.
+ */
+ pixelRect = QRectF();
+ }
+ }
+
+ if ( pixelRect.isEmpty() )
+ {
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ // we want to have maps, where the boundaries of
+ // the aligned paint rectangle exactly match the area
+
+ paintRect = qwtAlignRect(paintRect);
+ adjustMaps(xxMap, yyMap, area, paintRect);
+ }
+
+ // When we have no information about position and size of
+ // data pixels we render in resolution of the paint device.
+
+ image = compose(xxMap, yyMap,
+ area, paintRect, paintRect.size().toSize(), doCache);
+ if ( image.isNull() )
+ return;
+
+ // Remove pixels at the boundaries, when explicitly
+ // excluded in the intervals
+
+ imageRect = qwtStripRect(paintRect, area,
+ xxMap, yyMap, xInterval, yInterval);
+
+ if ( imageRect != paintRect )
+ {
+ const QRect r(
+ qRound( imageRect.x() - paintRect.x()),
+ qRound( imageRect.y() - paintRect.y() ),
+ qRound( imageRect.width() ),
+ qRound( imageRect.height() ) );
+
+ image = image.copy(r);
+ }
+ }
+ else
+ {
+ if ( QwtPainter::roundingAlignment( painter ) )
+ paintRect = qwtAlignRect(paintRect);
+
+ // align the area to the data pixels
+ QRectF imageArea = expandToPixels(area, pixelRect);
+
+ if ( imageArea.right() == xInterval.maxValue() &&
+ !( xInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
+ {
+ imageArea.adjust(0, 0, pixelRect.width(), 0);
+ }
+ if ( imageArea.bottom() == yInterval.maxValue() &&
+ !( yInterval.borderFlags() & QwtInterval::ExcludeMaximum ) )
+ {
+ imageArea.adjust(0, 0, 0, pixelRect.height() );
+ }
+
+ QSize imageSize;
+ imageSize.setWidth( qRound( imageArea.width() / pixelRect.width() ) );
+ imageSize.setHeight( qRound( imageArea.height() / pixelRect.height() ) );
+ image = compose(xxMap, yyMap,
+ imageArea, paintRect, imageSize, doCache );
+ if ( image.isNull() )
+ return;
+
+ imageRect = qwtStripRect(paintRect, area,
+ xxMap, yyMap, xInterval, yInterval);
+
+ if ( ( image.width() > 1 || image.height() > 1 ) &&
+ testPaintAttribute( PaintInDeviceResolution ) )
+ {
+ // Because of rounding errors the pixels
+ // need to be expanded manually to rectangles of
+ // different sizes
+
+ image = qwtExpandImage(image, xxMap, yyMap,
+ imageArea, area, paintRect, xInterval, yInterval );
+ }
+ }
+
+ painter->save();
+ painter->setWorldTransform( QTransform() );
+
+ QwtPainter::drawImage( painter, imageRect, image );
+
+ painter->restore();
+}
+
+/*!
+ \return Bounding interval for an axis
+
+ This method is intended to be reimplemented by derived classes.
+ The default implementation returns an invalid interval.
+
+ \param axis X, Y, or Z axis
+*/
+QwtInterval QwtPlotRasterItem::interval(Qt::Axis axis) const
+{
+ Q_UNUSED( axis );
+ return QwtInterval();
+}
+
+/*!
+ \return Bounding rect of the data
+ \sa QwtPlotRasterItem::interval()
+*/
+QRectF QwtPlotRasterItem::boundingRect() const
+{
+ const QwtInterval intervalX = interval( Qt::XAxis );
+ const QwtInterval intervalY = interval( Qt::YAxis );
+
+ if ( !intervalX.isValid() && !intervalY.isValid() )
+ return QRectF(); // no bounding rect
+
+ QRectF r;
+
+ if ( intervalX.isValid() )
+ {
+ r.setLeft( intervalX.minValue() );
+ r.setRight( intervalX.maxValue() );
+ }
+ else
+ {
+ r.setLeft(-0.5 * FLT_MAX);
+ r.setWidth(FLT_MAX);
+ }
+
+ if ( intervalY.isValid() )
+ {
+ r.setTop( intervalY.minValue() );
+ r.setBottom( intervalY.maxValue() );
+ }
+ else
+ {
+ r.setTop(-0.5 * FLT_MAX);
+ r.setHeight(FLT_MAX);
+ }
+
+ return r.normalized();
+}
+
+QImage QwtPlotRasterItem::compose(
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &imageArea, const QRectF &paintRect,
+ const QSize &imageSize, bool doCache) const
+{
+ QImage image;
+ if ( imageArea.isEmpty() || paintRect.isEmpty() || imageSize.isEmpty() )
+ return image;
+
+ if ( doCache )
+ {
+ if ( !d_data->cache.image.isNull()
+ && d_data->cache.area == imageArea
+ && d_data->cache.size == paintRect.size() )
+ {
+ image = d_data->cache.image;
+ }
+ }
+
+ if ( image.isNull() )
+ {
+ double dx = 0.0;
+ if ( paintRect.toRect().width() > imageSize.width() )
+ dx = imageArea.width() / imageSize.width();
+
+ const QwtScaleMap xxMap =
+ imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
+
+ double dy = 0.0;
+ if ( paintRect.toRect().height() > imageSize.height() )
+ dy = imageArea.height() / imageSize.height();
+
+ const QwtScaleMap yyMap =
+ imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);
+
+ image = renderImage( xxMap, yyMap, imageArea, imageSize );
+
+ if ( doCache )
+ {
+ d_data->cache.area = imageArea;
+ d_data->cache.size = paintRect.size();
+ d_data->cache.image = image;
+ }
+ }
+
+ if ( d_data->alpha >= 0 && d_data->alpha < 255 )
+ image = toRgba( image, d_data->alpha );
+
+ return image;
+}
+
+/*!
+ \brief Calculate a scale map for painting to an image
+
+ \param orientation Orientation, Qt::Horizontal means a X axis
+ \param map Scale map for rendering the plot item
+ \param area Area to be painted on the image
+ \param imageSize Image size
+ \param pixelSize Width/Height of a data pixel
+*/
+QwtScaleMap QwtPlotRasterItem::imageMap(
+ Qt::Orientation orientation,
+ const QwtScaleMap &map, const QRectF &area,
+ const QSize &imageSize, double pixelSize) const
+{
+ double p1, p2, s1, s2;
+
+ if ( orientation == Qt::Horizontal )
+ {
+ p1 = 0.0;
+ p2 = imageSize.width();
+ s1 = area.left();
+ s2 = area.right();
+ }
+ else
+ {
+ p1 = 0.0;
+ p2 = imageSize.height();
+ s1 = area.top();
+ s2 = area.bottom();
+ }
+
+ if ( pixelSize > 0.0 )
+ {
+ double off = 0.5 * pixelSize;
+ if ( map.isInverting() )
+ off = -off;
+
+ s1 += off;
+ s2 += off;
+ }
+ else
+ {
+ p2--;
+ }
+
+ if ( map.isInverting() && ( s1 < s2 ) )
+ qSwap( s1, s2 );
+
+ QwtScaleMap newMap = map;
+ newMap.setPaintInterval( p1, p2 );
+ newMap.setScaleInterval( s1, s2 );
+
+ return newMap;
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_rasteritem.h b/src/libpcp_qwt/src/qwt_plot_rasteritem.h
new file mode 100644
index 0000000..b2292d8
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_rasteritem.h
@@ -0,0 +1,146 @@
+/* -*- 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_PLOT_RASTERITEM_H
+#define QWT_PLOT_RASTERITEM_H
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include "qwt_interval.h"
+#include <qglobal.h>
+#include <qstring.h>
+#include <qimage.h>
+
+/*!
+ \brief A class, which displays raster data
+
+ Raster data is a grid of pixel values, that can be represented
+ as a QImage. It is used for many types of information like
+ spectrograms, cartograms, geographical maps ...
+
+ Often a plot has several types of raster data organized in layers.
+ ( f.e a geographical map, with weather statistics ).
+ Using setAlpha() raster items can be stacked easily.
+
+ QwtPlotRasterItem is only implemented for images of the following formats:
+ QImage::Format_Indexed8, QImage::Format_ARGB32.
+
+ \sa QwtPlotSpectrogram
+*/
+
+class QWT_EXPORT QwtPlotRasterItem: public QwtPlotItem
+{
+public:
+ /*!
+ - NoCache\n
+ renderImage() is called, whenever the item has to be repainted
+ - PaintCache\n
+ renderImage() is called, whenever the image cache is not valid,
+ or the scales, or the size of the canvas has changed. This type
+ of cache is only useful for improving the performance of hide/show
+ operations. All other situations are already handled by the
+ plot canvas cache.
+
+ The default policy is NoCache
+ */
+ enum CachePolicy
+ {
+ NoCache,
+ PaintCache
+ };
+
+ /*!
+ Attributes to modify the drawing algorithm.
+ \sa setPaintAttribute(), testPaintAttribute()
+ */
+ enum PaintAttribute
+ {
+ /*!
+ When the image is rendered according to the data pixels
+ ( QwtRasterData::pixelHint() ) it can be expanded to paint
+ device resolution before it is passed to QPainter.
+ The expansion algorithm rounds the pixel borders in the same
+ way as the axis ticks, what is usually better than the
+ scaling algorithm implemented in Qt.
+ Disabling this flag might make sense, to reduce the size of a
+ document/file. If this is possible for a document format
+ depends on the implementation of the specific QPaintEngine.
+ */
+
+ PaintInDeviceResolution = 1
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ explicit QwtPlotRasterItem( const QString& title = QString::null );
+ explicit QwtPlotRasterItem( const QwtText& title );
+ virtual ~QwtPlotRasterItem();
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ void setAlpha( int alpha );
+ int alpha() const;
+
+ void setCachePolicy( CachePolicy );
+ CachePolicy cachePolicy() const;
+
+ void invalidateCache();
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &rect ) const;
+
+ virtual QRectF pixelHint( const QRectF & ) const;
+
+ virtual QwtInterval interval(Qt::Axis) const;
+ virtual QRectF boundingRect() const;
+
+protected:
+ /*!
+ \brief Render an image
+
+ An implementation of render() might iterate over all
+ pixels of imageRect. Each pixel has to be translated into
+ the corresponding position in scale coordinates using the maps.
+ This position can be used to look up a value in a implementation
+ specific way and to map it into a color.
+
+ \param xMap X-Scale Map
+ \param yMap Y-Scale Map
+ \param area Requested area for the image in scale coordinates
+ \param imageSize Requested size of the image
+ */
+ virtual QImage renderImage( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap, const QRectF &area,
+ const QSize &imageSize ) const = 0;
+
+ virtual QwtScaleMap imageMap( Qt::Orientation,
+ const QwtScaleMap &map, const QRectF &area,
+ const QSize &imageSize, double pixelSize) const;
+
+private:
+ QwtPlotRasterItem( const QwtPlotRasterItem & );
+ QwtPlotRasterItem &operator=( const QwtPlotRasterItem & );
+
+ void init();
+
+ QImage compose( const QwtScaleMap &, const QwtScaleMap &,
+ const QRectF &imageArea, const QRectF &paintRect,
+ const QSize &imageSize, bool doCache) const;
+
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotRasterItem::PaintAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_renderer.cpp b/src/libpcp_qwt/src/qwt_plot_renderer.cpp
new file mode 100644
index 0000000..4dfbfec
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_renderer.cpp
@@ -0,0 +1,897 @@
+/* -*- 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_plot_renderer.h"
+#include "qwt_plot.h"
+#include "qwt_painter.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_plot_layout.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_dyngrid_layout.h"
+#include "qwt_scale_widget.h"
+#include "qwt_scale_engine.h"
+#include "qwt_text.h"
+#include "qwt_text_label.h"
+#include "qwt_math.h"
+#include <qpainter.h>
+#include <qpaintengine.h>
+#include <qtransform.h>
+#include <qprinter.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qimagewriter.h>
+#include <qfileinfo.h>
+#ifndef QWT_NO_SVG
+#ifdef QT_SVG_LIB
+#include <qsvggenerator.h>
+#endif
+#endif
+
+class QwtPlotRenderer::PrivateData
+{
+public:
+ PrivateData():
+ discardFlags( QwtPlotRenderer::DiscardBackground ),
+ layoutFlags( QwtPlotRenderer::DefaultLayout )
+ {
+ }
+
+ QwtPlotRenderer::DiscardFlags discardFlags;
+ QwtPlotRenderer::LayoutFlags layoutFlags;
+};
+
+static void qwtRenderBackground( QPainter *painter,
+ const QRectF &rect, const QWidget *widget )
+{
+ if ( widget->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ QStyleOption opt;
+ opt.initFrom( widget );
+ opt.rect = rect.toAlignedRect();
+
+ widget->style()->drawPrimitive(
+ QStyle::PE_Widget, &opt, painter, widget);
+ }
+ else
+ {
+ const QBrush brush =
+ widget->palette().brush( widget->backgroundRole() );
+
+ painter->fillRect( rect, brush );
+ }
+}
+
+/*!
+ Constructor
+ \param parent Parent object
+*/
+QwtPlotRenderer::QwtPlotRenderer( QObject *parent ):
+ QObject( parent )
+{
+ d_data = new PrivateData;
+}
+
+//! Destructor
+QwtPlotRenderer::~QwtPlotRenderer()
+{
+ delete d_data;
+}
+
+/*!
+ Change a flag, indicating what to discard from rendering
+
+ \param flag Flag to change
+ \param on On/Off
+
+ \sa DiscardFlag, testDiscardFlag(), setDiscardFlags(), discardFlags()
+*/
+void QwtPlotRenderer::setDiscardFlag( DiscardFlag flag, bool on )
+{
+ if ( on )
+ d_data->discardFlags |= flag;
+ else
+ d_data->discardFlags &= ~flag;
+}
+
+/*!
+ Check if a flag is set.
+
+ \param flag Flag to be tested
+ \sa DiscardFlag, setDiscardFlag(), setDiscardFlags(), discardFlags()
+*/
+bool QwtPlotRenderer::testDiscardFlag( DiscardFlag flag ) const
+{
+ return d_data->discardFlags & flag;
+}
+
+/*!
+ Set the flags, indicating what to discard from rendering
+
+ \param flags Flags
+ \sa DiscardFlag, setDiscardFlag(), testDiscardFlag(), discardFlags()
+*/
+void QwtPlotRenderer::setDiscardFlags( DiscardFlags flags )
+{
+ d_data->discardFlags = flags;
+}
+
+/*!
+ \return Flags, indicating what to discard from rendering
+ \sa DiscardFlag, setDiscardFlags(), setDiscardFlag(), testDiscardFlag()
+*/
+QwtPlotRenderer::DiscardFlags QwtPlotRenderer::discardFlags() const
+{
+ return d_data->discardFlags;
+}
+
+/*!
+ Change a layout flag
+
+ \param flag Flag to change
+ \param on On/Off
+
+ \sa LayoutFlag, testLayoutFlag(), setLayoutFlags(), layoutFlags()
+*/
+void QwtPlotRenderer::setLayoutFlag( LayoutFlag flag, bool on )
+{
+ if ( on )
+ d_data->layoutFlags |= flag;
+ else
+ d_data->layoutFlags &= ~flag;
+}
+
+/*!
+ Check if a flag is set.
+
+ \param flag Flag to be tested
+ \sa LayoutFlag, setLayoutFlag(), setLayoutFlags(), layoutFlags()
+*/
+bool QwtPlotRenderer::testLayoutFlag( LayoutFlag flag ) const
+{
+ return d_data->layoutFlags & flag;
+}
+
+/*!
+ Set the layout flags
+
+ \param flags Flags
+ \sa LayoutFlag, setLayoutFlag(), testLayoutFlag(), layoutFlags()
+*/
+void QwtPlotRenderer::setLayoutFlags( LayoutFlags flags )
+{
+ d_data->layoutFlags = flags;
+}
+
+/*!
+ \return Layout flags
+ \sa LayoutFlag, setLayoutFlags(), setLayoutFlag(), testLayoutFlag()
+*/
+QwtPlotRenderer::LayoutFlags QwtPlotRenderer::layoutFlags() const
+{
+ return d_data->layoutFlags;
+}
+
+/*!
+ Render a plot to a file
+
+ The format of the document will be autodetected from the
+ suffix of the filename.
+
+ \param plot Plot widget
+ \param fileName Path of the file, where the document will be stored
+ \param sizeMM Size for the document in millimeters.
+ \param resolution Resolution in dots per Inch (dpi)
+*/
+void QwtPlotRenderer::renderDocument( QwtPlot *plot,
+ const QString &fileName, const QSizeF &sizeMM, int resolution )
+{
+ renderDocument( plot, fileName,
+ QFileInfo( fileName ).suffix(), sizeMM, resolution );
+}
+
+/*!
+ Render a plot to a file
+
+ Supported formats are:
+
+ - pdf\n
+ Portable Document Format PDF
+ - ps\n
+ Postcript
+ - svg\n
+ Scalable Vector Graphics SVG
+ - all image formats supported by Qt\n
+ see QImageWriter::supportedImageFormats()
+
+ Scalable vector graphic formats like PDF or SVG are superior to
+ raster graphics formats.
+
+ \param plot Plot widget
+ \param fileName Path of the file, where the document will be stored
+ \param format Format for the document
+ \param sizeMM Size for the document in millimeters.
+ \param resolution Resolution in dots per Inch (dpi)
+
+ \sa renderTo(), render(), QwtPainter::setRoundingAlignment()
+*/
+void QwtPlotRenderer::renderDocument( QwtPlot *plot,
+ const QString &fileName, const QString &format,
+ const QSizeF &sizeMM, int resolution )
+{
+ if ( plot == NULL || sizeMM.isEmpty() || resolution <= 0 )
+ return;
+
+ QString title = plot->title().text();
+ if ( title.isEmpty() )
+ title = "Plot Document";
+
+ const double mmToInch = 1.0 / 25.4;
+ const QSizeF size = sizeMM * mmToInch * resolution;
+
+ const QRectF documentRect( 0.0, 0.0, size.width(), size.height() );
+
+ const QString fmt = format.toLower();
+ if ( fmt == "pdf" )
+ {
+#ifndef QT_NO_PRINTER
+ QPrinter printer;
+ printer.setFullPage( true );
+ printer.setPaperSize( sizeMM, QPrinter::Millimeter );
+ printer.setDocName( title );
+ printer.setOutputFileName( fileName );
+ printer.setOutputFormat( QPrinter::PdfFormat );
+ printer.setResolution( resolution );
+
+ QPainter painter( &printer );
+ render( plot, &painter, documentRect );
+#endif
+ }
+ else if ( fmt == "ps" )
+ {
+#if QT_VERSION < 0x050000
+#ifndef QT_NO_PRINTER
+ QPrinter printer;
+ printer.setFullPage( true );
+ printer.setPaperSize( sizeMM, QPrinter::Millimeter );
+ printer.setDocName( title );
+ printer.setOutputFileName( fileName );
+ printer.setOutputFormat( QPrinter::PostScriptFormat );
+ printer.setResolution( resolution );
+
+ QPainter painter( &printer );
+ render( plot, &painter, documentRect );
+#endif
+#endif
+ }
+ else if ( fmt == "svg" )
+ {
+#ifndef QWT_NO_SVG
+#ifdef QT_SVG_LIB
+#if QT_VERSION >= 0x040500
+ QSvgGenerator generator;
+ generator.setTitle( title );
+ generator.setFileName( fileName );
+ generator.setResolution( resolution );
+ generator.setViewBox( documentRect );
+
+ QPainter painter( &generator );
+ render( plot, &painter, documentRect );
+#endif
+#endif
+#endif
+ }
+ else
+ {
+ if ( QImageWriter::supportedImageFormats().indexOf(
+ format.toLatin1() ) >= 0 )
+ {
+ const QRect imageRect = documentRect.toRect();
+ const int dotsPerMeter = qRound( resolution * mmToInch * 1000.0 );
+
+ QImage image( imageRect.size(), QImage::Format_ARGB32 );
+ image.setDotsPerMeterX( dotsPerMeter );
+ image.setDotsPerMeterY( dotsPerMeter );
+ image.fill( QColor( Qt::white ).rgb() );
+
+ QPainter painter( &image );
+ render( plot, &painter, imageRect );
+ painter.end();
+
+ image.save( fileName, format.toLatin1() );
+ }
+ }
+}
+
+/*!
+ \brief Render the plot to a \c QPaintDevice
+
+ This function renders the contents of a QwtPlot instance to
+ \c QPaintDevice object. The target rectangle is derived from
+ its device metrics.
+
+ \param plot Plot to be rendered
+ \param paintDevice device to paint on, f.e a QImage
+
+ \sa renderDocument(), render(), QwtPainter::setRoundingAlignment()
+*/
+
+void QwtPlotRenderer::renderTo(
+ QwtPlot *plot, QPaintDevice &paintDevice ) const
+{
+ int w = paintDevice.width();
+ int h = paintDevice.height();
+
+ QPainter p( &paintDevice );
+ render( plot, &p, QRectF( 0, 0, w, h ) );
+}
+
+/*!
+ \brief Render the plot to a QPrinter
+
+ This function renders the contents of a QwtPlot instance to
+ \c QPaintDevice object. The size is derived from the printer
+ metrics.
+
+ \param plot Plot to be rendered
+ \param printer Printer to paint on
+
+ \sa renderDocument(), render(), QwtPainter::setRoundingAlignment()
+*/
+
+#ifndef QT_NO_PRINTER
+
+void QwtPlotRenderer::renderTo(
+ QwtPlot *plot, QPrinter &printer ) const
+{
+ int w = printer.width();
+ int h = printer.height();
+
+ QRectF rect( 0, 0, w, h );
+ double aspect = rect.width() / rect.height();
+ if ( ( aspect < 1.0 ) )
+ rect.setHeight( aspect * rect.width() );
+
+ QPainter p( &printer );
+ render( plot, &p, rect );
+}
+
+#endif
+
+#ifndef QWT_NO_SVG
+#ifdef QT_SVG_LIB
+#if QT_VERSION >= 0x040500
+
+/*!
+ \brief Render the plot to a QSvgGenerator
+
+ If the generator has a view box, the plot will be rendered into it.
+ If it has no viewBox but a valid size the target coordinates
+ will be (0, 0, generator.width(), generator.height()). Otherwise
+ the target rectangle will be QRectF(0, 0, 800, 600);
+
+ \param plot Plot to be rendered
+ \param generator SVG generator
+*/
+void QwtPlotRenderer::renderTo(
+ QwtPlot *plot, QSvgGenerator &generator ) const
+{
+ QRectF rect = generator.viewBoxF();
+ if ( rect.isEmpty() )
+ rect.setRect( 0, 0, generator.width(), generator.height() );
+
+ if ( rect.isEmpty() )
+ rect.setRect( 0, 0, 800, 600 ); // something
+
+ QPainter p( &generator );
+ render( plot, &p, rect );
+}
+#endif
+#endif
+#endif
+
+/*!
+ Paint the contents of a QwtPlot instance into a given rectangle.
+
+ \param plot Plot to be rendered
+ \param painter Painter
+ \param plotRect Bounding rectangle
+
+ \sa renderDocument(), renderTo(), QwtPainter::setRoundingAlignment()
+*/
+void QwtPlotRenderer::render( QwtPlot *plot,
+ QPainter *painter, const QRectF &plotRect ) const
+{
+ int axisId;
+
+ if ( painter == 0 || !painter->isActive() ||
+ !plotRect.isValid() || plot->size().isNull() )
+ return;
+
+ if ( !( d_data->discardFlags & DiscardBackground ) )
+ qwtRenderBackground( painter, plotRect, plot );
+
+ /*
+ The layout engine uses the same methods as they are used
+ by the Qt layout system. Therefore we need to calculate the
+ layout in screen coordinates and paint with a scaled painter.
+ */
+ QTransform transform;
+ transform.scale(
+ double( painter->device()->logicalDpiX() ) / plot->logicalDpiX(),
+ double( painter->device()->logicalDpiY() ) / plot->logicalDpiY() );
+
+
+ QRectF layoutRect = transform.inverted().mapRect( plotRect );
+
+ if ( !( d_data->discardFlags & DiscardBackground ) )
+ {
+ // subtract the contents margins
+
+ int left, top, right, bottom;
+ plot->getContentsMargins( &left, &top, &right, &bottom );
+ layoutRect.adjust( left, top, -right, -bottom );
+ }
+
+ int baseLineDists[QwtPlot::axisCnt];
+ if ( d_data->layoutFlags & FrameWithScales )
+ {
+ for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
+ {
+ QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
+ if ( scaleWidget )
+ {
+ baseLineDists[axisId] = scaleWidget->margin();
+ scaleWidget->setMargin( 0 );
+ }
+
+ if ( !plot->axisEnabled( axisId ) )
+ {
+ int left = 0;
+ int right = 0;
+ int top = 0;
+ int bottom = 0;
+
+ // When we have a scale the frame is painted on
+ // the position of the backbone - otherwise we
+ // need to introduce a margin around the canvas
+
+ switch( axisId )
+ {
+ case QwtPlot::yLeft:
+ layoutRect.adjust( 1, 0, 0, 0 );
+ break;
+ case QwtPlot::yRight:
+ layoutRect.adjust( 0, 0, -1, 0 );
+ break;
+ case QwtPlot::xTop:
+ layoutRect.adjust( 0, 1, 0, 0 );
+ break;
+ case QwtPlot::xBottom:
+ layoutRect.adjust( 0, 0, 0, -1 );
+ break;
+ default:
+ break;
+ }
+ layoutRect.adjust( left, top, right, bottom );
+ }
+ }
+ }
+
+ // Calculate the layout for the document.
+
+ QwtPlotLayout::Options layoutOptions =
+ QwtPlotLayout::IgnoreScrollbars | QwtPlotLayout::IgnoreFrames;
+
+ if ( d_data->discardFlags & DiscardLegend )
+ layoutOptions |= QwtPlotLayout::IgnoreLegend;
+
+ plot->plotLayout()->activate( plot, layoutRect, layoutOptions );
+
+ // now start painting
+
+ painter->save();
+ painter->setWorldTransform( transform, true );
+
+ // canvas
+
+ QwtScaleMap maps[QwtPlot::axisCnt];
+ buildCanvasMaps( plot, plot->plotLayout()->canvasRect(), maps );
+ renderCanvas( plot, painter, plot->plotLayout()->canvasRect(), maps );
+
+ if ( !( d_data->discardFlags & DiscardTitle )
+ && ( !plot->titleLabel()->text().isEmpty() ) )
+ {
+ renderTitle( plot, painter, plot->plotLayout()->titleRect() );
+ }
+
+ if ( !( d_data->discardFlags & DiscardLegend )
+ && plot->legend() && !plot->legend()->isEmpty() )
+ {
+ renderLegend( plot, painter, plot->plotLayout()->legendRect() );
+ }
+
+ for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
+ {
+ QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
+ if ( scaleWidget )
+ {
+ int baseDist = scaleWidget->margin();
+
+ int startDist, endDist;
+ scaleWidget->getBorderDistHint( startDist, endDist );
+
+ renderScale( plot, painter, axisId, startDist, endDist,
+ baseDist, plot->plotLayout()->scaleRect( axisId ) );
+ }
+ }
+
+
+ plot->plotLayout()->invalidate();
+
+ // reset all widgets with their original attributes.
+ if ( d_data->layoutFlags & FrameWithScales )
+ {
+ // restore the previous base line dists
+
+ for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
+ {
+ QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
+ if ( scaleWidget )
+ scaleWidget->setMargin( baseLineDists[axisId] );
+ }
+ }
+
+ painter->restore();
+}
+
+/*!
+ Render the title into a given rectangle.
+
+ \param plot Plot widget
+ \param painter Painter
+ \param rect Bounding rectangle
+*/
+void QwtPlotRenderer::renderTitle( const QwtPlot *plot,
+ QPainter *painter, const QRectF &rect ) const
+{
+ painter->setFont( plot->titleLabel()->font() );
+
+ const QColor color = plot->titleLabel()->palette().color(
+ QPalette::Active, QPalette::Text );
+
+ painter->setPen( color );
+ plot->titleLabel()->text().draw( painter, rect );
+}
+
+/*!
+ Render the legend into a given rectangle.
+
+ \param plot Plot widget
+ \param painter Painter
+ \param rect Bounding rectangle
+*/
+void QwtPlotRenderer::renderLegend( const QwtPlot *plot,
+ QPainter *painter, const QRectF &rect ) const
+{
+ if ( !plot->legend() || plot->legend()->isEmpty() )
+ return;
+
+ if ( !( d_data->discardFlags & DiscardBackground ) )
+ {
+ if ( plot->legend()->autoFillBackground() ||
+ plot->legend()->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ qwtRenderBackground( painter, rect, plot->legend() );
+ }
+ }
+
+ const QwtDynGridLayout *legendLayout = qobject_cast<QwtDynGridLayout *>(
+ plot->legend()->contentsWidget()->layout() );
+ if ( legendLayout == NULL )
+ return;
+
+ uint numCols = legendLayout->columnsForWidth( qFloor( rect.width() ) );
+ QList<QRect> itemRects =
+ legendLayout->layoutItems( rect.toRect(), 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] );
+ renderLegendItem( plot, painter, w, itemRects[index] );
+
+ index++;
+ painter->restore();
+ }
+ }
+}
+
+/*!
+ Render the legend item into a given rectangle.
+
+ \param plot Plot widget
+ \param painter Painter
+ \param widget Widget representing a legend item
+ \param rect Bounding rectangle
+
+ \note When widget is not derived from QwtLegendItem renderLegendItem
+ does nothing and needs to be overloaded
+*/
+void QwtPlotRenderer::renderLegendItem( const QwtPlot *plot,
+ QPainter *painter, const QWidget *widget, const QRectF &rect ) const
+{
+ if ( !( d_data->discardFlags & DiscardBackground ) )
+ {
+ if ( widget->autoFillBackground() ||
+ widget->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ qwtRenderBackground( painter, rect, widget );
+ }
+ }
+
+ const QwtLegendItem *item = qobject_cast<const QwtLegendItem *>( widget );
+ if ( item )
+ {
+ const QSize sz = item->identifierSize();
+
+ const QRectF identifierRect( rect.x() + item->margin(),
+ rect.center().y() - 0.5 * sz.height(), sz.width(), sz.height() );
+
+ QwtLegendItemManager *itemManger = plot->legend()->find( item );
+ if ( itemManger )
+ {
+ painter->save();
+ painter->setClipRect( identifierRect, Qt::IntersectClip );
+ itemManger->drawLegendIdentifier( painter, identifierRect );
+ painter->restore();
+ }
+
+ // Label
+
+ QRectF titleRect = rect;
+ titleRect.setX( identifierRect.right() + 2 * item->spacing() );
+
+ painter->setFont( item->font() );
+ item->text().draw( painter, titleRect );
+ }
+}
+
+/*!
+ \brief Paint a scale into a given rectangle.
+ Paint the scale into a given rectangle.
+
+ \param plot Plot widget
+ \param painter Painter
+ \param axisId Axis
+ \param startDist Start border distance
+ \param endDist End border distance
+ \param baseDist Base distance
+ \param rect Bounding rectangle
+*/
+void QwtPlotRenderer::renderScale( const QwtPlot *plot,
+ QPainter *painter,
+ int axisId, int startDist, int endDist, int baseDist,
+ const QRectF &rect ) const
+{
+ if ( !plot->axisEnabled( axisId ) )
+ return;
+
+ const QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
+ if ( scaleWidget->isColorBarEnabled()
+ && scaleWidget->colorBarWidth() > 0 )
+ {
+ scaleWidget->drawColorBar( painter, scaleWidget->colorBarRect( rect ) );
+
+ const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
+ if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
+ baseDist += off;
+ else
+ baseDist += off;
+ }
+
+ painter->save();
+
+ QwtScaleDraw::Alignment align;
+ double x, y, w;
+
+ switch ( axisId )
+ {
+ case QwtPlot::yLeft:
+ {
+ x = rect.right() - 1.0 - baseDist;
+ y = rect.y() + startDist;
+ w = rect.height() - startDist - endDist;
+ align = QwtScaleDraw::LeftScale;
+ break;
+ }
+ case QwtPlot::yRight:
+ {
+ x = rect.left() + baseDist;
+ y = rect.y() + startDist;
+ w = rect.height() - startDist - endDist;
+ align = QwtScaleDraw::RightScale;
+ break;
+ }
+ case QwtPlot::xTop:
+ {
+ x = rect.left() + startDist;
+ y = rect.bottom() - 1.0 - baseDist;
+ w = rect.width() - startDist - endDist;
+ align = QwtScaleDraw::TopScale;
+ break;
+ }
+ case QwtPlot::xBottom:
+ {
+ x = rect.left() + startDist;
+ y = rect.top() + baseDist;
+ w = rect.width() - startDist - endDist;
+ align = QwtScaleDraw::BottomScale;
+ break;
+ }
+ default:
+ return;
+ }
+
+ scaleWidget->drawTitle( painter, align, rect );
+
+ painter->setFont( scaleWidget->font() );
+
+ QwtScaleDraw *sd = const_cast<QwtScaleDraw *>( scaleWidget->scaleDraw() );
+ const QPointF sdPos = sd->pos();
+ const double sdLength = sd->length();
+
+ sd->move( x, y );
+ sd->setLength( w );
+
+ QPalette palette = scaleWidget->palette();
+ palette.setCurrentColorGroup( QPalette::Active );
+ sd->draw( painter, palette );
+
+ // reset previous values
+ sd->move( sdPos );
+ sd->setLength( sdLength );
+
+ painter->restore();
+}
+
+/*!
+ Render the canvas into a given rectangle.
+
+ \param plot Plot widget
+ \param painter Painter
+ \param map Maps mapping between plot and paint device coordinates
+ \param canvasRect Canvas rectangle
+*/
+void QwtPlotRenderer::renderCanvas( const QwtPlot *plot,
+ QPainter *painter, const QRectF &canvasRect,
+ const QwtScaleMap *map ) const
+{
+ painter->save();
+
+ QPainterPath clipPath;
+
+ QRectF r = canvasRect.adjusted( 0.0, 0.0, -1.0, -1.0 );
+
+ if ( d_data->layoutFlags & FrameWithScales )
+ {
+ r.adjust( -1.0, -1.0, 1.0, 1.0 );
+ painter->setPen( QPen( Qt::black ) );
+
+ if ( !( d_data->discardFlags & DiscardCanvasBackground ) )
+ {
+ const QBrush bgBrush =
+ plot->canvas()->palette().brush( plot->backgroundRole() );
+ painter->setBrush( bgBrush );
+ }
+
+ QwtPainter::drawRect( painter, r );
+ }
+ else
+ {
+ if ( !( d_data->discardFlags & DiscardCanvasBackground ) )
+ {
+ qwtRenderBackground( painter, r, plot->canvas() );
+
+ if ( plot->canvas()->testAttribute( Qt::WA_StyledBackground ) )
+ {
+ // The clip region is calculated in integers
+ // To avoid too much rounding errors better
+ // calculate it in target device resolution
+ // TODO ...
+
+ int x1 = qCeil( canvasRect.left() );
+ int x2 = qFloor( canvasRect.right() );
+ int y1 = qCeil( canvasRect.top() );
+ int y2 = qFloor( canvasRect.bottom() );
+
+ clipPath = plot->canvas()->borderPath(
+ QRect( x1, y1, x2 - x1 - 1, y2 - y1 - 1 ) );
+ }
+ }
+ }
+
+ painter->restore();
+
+ painter->save();
+
+ if ( clipPath.isEmpty() )
+ painter->setClipRect( canvasRect );
+ else
+ painter->setClipPath( clipPath );
+
+ plot->drawItems( painter, canvasRect, map );
+
+ painter->restore();
+}
+
+/*!
+ Calculated the scale maps for rendering the canvas
+
+ \param plot Plot widget
+ \param canvasRect Target rectangle
+ \param maps Scale maps to be calculated
+*/
+void QwtPlotRenderer::buildCanvasMaps( const QwtPlot *plot,
+ const QRectF &canvasRect, QwtScaleMap maps[] ) const
+{
+ for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
+ {
+ maps[axisId].setTransformation(
+ plot->axisScaleEngine( axisId )->transformation() );
+
+ const QwtScaleDiv &scaleDiv = *plot->axisScaleDiv( axisId );
+ maps[axisId].setScaleInterval(
+ scaleDiv.lowerBound(), scaleDiv.upperBound() );
+
+ double from, to;
+ if ( plot->axisEnabled( axisId ) )
+ {
+ const int sDist = plot->axisWidget( axisId )->startBorderDist();
+ const int eDist = plot->axisWidget( axisId )->endBorderDist();
+ const QRectF &scaleRect = plot->plotLayout()->scaleRect( axisId );
+
+ if ( axisId == QwtPlot::xTop || axisId == QwtPlot::xBottom )
+ {
+ from = scaleRect.left() + sDist;
+ to = scaleRect.right() - eDist;
+ }
+ else
+ {
+ from = scaleRect.bottom() - eDist;
+ to = scaleRect.top() + sDist;
+ }
+ }
+ else
+ {
+ int margin = 0;
+ if ( !plot->plotLayout()->alignCanvasToScales() )
+ margin = plot->plotLayout()->canvasMargin( axisId );
+
+ if ( axisId == QwtPlot::yLeft || axisId == QwtPlot::yRight )
+ {
+ from = canvasRect.bottom() - margin;
+ to = canvasRect.top() + margin;
+ }
+ else
+ {
+ from = canvasRect.left() + margin;
+ to = canvasRect.right() - margin;
+ }
+ }
+ maps[axisId].setPaintInterval( from, to );
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_renderer.h b/src/libpcp_qwt/src/qwt_plot_renderer.h
new file mode 100644
index 0000000..f79146a
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_renderer.h
@@ -0,0 +1,154 @@
+/* -*- 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_PLOT_RENDERER_H
+#define QWT_PLOT_RENDERER_H
+
+#include "qwt_global.h"
+#include <qobject.h>
+
+class QwtPlot;
+class QwtScaleMap;
+class QSizeF;
+class QRectF;
+class QPainter;
+class QPaintDevice;
+
+#ifndef QT_NO_PRINTER
+class QPrinter;
+#endif
+
+#ifndef QWT_NO_SVG
+#ifdef QT_SVG_LIB
+class QSvgGenerator;
+#endif
+#endif
+
+/*!
+ \brief Renderer for exporting a plot to a document, a printer
+ or anything else, that is supported by QPainter/QPaintDevice
+*/
+class QWT_EXPORT QwtPlotRenderer: public QObject
+{
+ Q_OBJECT
+
+public:
+ //! Disard flags
+ enum DiscardFlag
+ {
+ //! Render all components of the plot
+ DiscardNone = 0x00,
+
+ //! Don't render the background of the plot
+ DiscardBackground = 0x01,
+
+ //! Don't render the title of the plot
+ DiscardTitle = 0x02,
+
+ //! Don't render the legend of the plot
+ DiscardLegend = 0x04,
+
+ //! Don't render the background of the canvas
+ DiscardCanvasBackground = 0x08
+ };
+
+ //! Disard flags
+ typedef QFlags<DiscardFlag> DiscardFlags;
+
+ /*!
+ \brief Layout flags
+ \sa setLayoutFlag(), testLayoutFlag()
+ */
+ enum LayoutFlag
+ {
+ //! Use the default layout without margins and frames
+ DefaultLayout = 0x00,
+
+ //! Render all frames of the plot
+ KeepFrames = 0x01,
+
+ /*!
+ Instead of the scales a box is painted around the plot canvas,
+ where the scale ticks are aligned to.
+ */
+ FrameWithScales = 0x02
+ };
+
+ //! Layout flags
+ typedef QFlags<LayoutFlag> LayoutFlags;
+
+ explicit QwtPlotRenderer( QObject * = NULL );
+ virtual ~QwtPlotRenderer();
+
+ void setDiscardFlag( DiscardFlag flag, bool on = true );
+ bool testDiscardFlag( DiscardFlag flag ) const;
+
+ void setDiscardFlags( DiscardFlags flags );
+ DiscardFlags discardFlags() const;
+
+ void setLayoutFlag( LayoutFlag flag, bool on = true );
+ bool testLayoutFlag( LayoutFlag flag ) const;
+
+ void setLayoutFlags( LayoutFlags flags );
+ LayoutFlags layoutFlags() const;
+
+ void renderDocument( QwtPlot *, const QString &fileName,
+ const QSizeF &sizeMM, int resolution = 85 );
+
+ void renderDocument( QwtPlot *,
+ const QString &fileName, const QString &format,
+ const QSizeF &sizeMM, int resolution = 85 );
+
+#ifndef QWT_NO_SVG
+#ifdef QT_SVG_LIB
+#if QT_VERSION >= 0x040500
+ void renderTo( QwtPlot *, QSvgGenerator & ) const;
+#endif
+#endif
+#endif
+
+#ifndef QT_NO_PRINTER
+ void renderTo( QwtPlot *, QPrinter & ) const;
+#endif
+
+ void renderTo( QwtPlot *, QPaintDevice &p ) const;
+
+ virtual void render( QwtPlot *,
+ QPainter *, const QRectF &rect ) const;
+
+ virtual void renderLegendItem( const QwtPlot *,
+ QPainter *, const QWidget *, const QRectF & ) const;
+
+ virtual void renderTitle( const QwtPlot *,
+ QPainter *, const QRectF & ) const;
+
+ virtual void renderScale( const QwtPlot *, QPainter *,
+ int axisId, int startDist, int endDist,
+ int baseDist, const QRectF & ) const;
+
+ virtual void renderCanvas( const QwtPlot *,
+ QPainter *, const QRectF &canvasRect,
+ const QwtScaleMap* maps ) const;
+
+ virtual void renderLegend(
+ const QwtPlot *, QPainter *, const QRectF & ) const;
+
+protected:
+ void buildCanvasMaps( const QwtPlot *,
+ const QRectF &, QwtScaleMap maps[] ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotRenderer::DiscardFlags )
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotRenderer::LayoutFlags )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_rescaler.cpp b/src/libpcp_qwt/src/qwt_plot_rescaler.cpp
new file mode 100644
index 0000000..69c0f4f
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_rescaler.cpp
@@ -0,0 +1,628 @@
+/* -*- 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_plot_rescaler.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_div.h"
+#include "qwt_interval.h"
+#include <qevent.h>
+#include <qalgorithms.h>
+
+class QwtPlotRescaler::AxisData
+{
+public:
+ AxisData():
+ aspectRatio( 1.0 ),
+ expandingDirection( QwtPlotRescaler::ExpandUp )
+ {
+ }
+
+ double aspectRatio;
+ QwtInterval intervalHint;
+ QwtPlotRescaler::ExpandingDirection expandingDirection;
+ mutable QwtScaleDiv scaleDiv;
+};
+
+class QwtPlotRescaler::PrivateData
+{
+public:
+ PrivateData():
+ referenceAxis( QwtPlot::xBottom ),
+ rescalePolicy( QwtPlotRescaler::Expanding ),
+ isEnabled( false ),
+ inReplot( 0 )
+ {
+ }
+
+ int referenceAxis;
+ RescalePolicy rescalePolicy;
+ QwtPlotRescaler::AxisData axisData[QwtPlot::axisCnt];
+ bool isEnabled;
+
+ mutable int inReplot;
+};
+
+/*!
+ Constructor
+
+ \param canvas Canvas
+ \param referenceAxis Reference axis, see RescalePolicy
+ \param policy Rescale policy
+
+ \sa setRescalePolicy(), setReferenceAxis()
+*/
+QwtPlotRescaler::QwtPlotRescaler( QwtPlotCanvas *canvas,
+ int referenceAxis, RescalePolicy policy ):
+ QObject( canvas )
+{
+ d_data = new PrivateData;
+ d_data->referenceAxis = referenceAxis;
+ d_data->rescalePolicy = policy;
+
+ setEnabled( true );
+}
+
+//! Destructor
+QwtPlotRescaler::~QwtPlotRescaler()
+{
+ delete d_data;
+}
+
+/*!
+ \brief En/disable the rescaler
+
+ When enabled is true an event filter is installed for
+ the canvas, otherwise the event filter is removed.
+
+ \param on true or false
+ \sa isEnabled(), eventFilter()
+*/
+void QwtPlotRescaler::setEnabled( bool on )
+{
+ if ( d_data->isEnabled != on )
+ {
+ d_data->isEnabled = on;
+
+ QWidget *w = canvas();
+ if ( w )
+ {
+ if ( d_data->isEnabled )
+ w->installEventFilter( this );
+ else
+ w->removeEventFilter( this );
+ }
+ }
+}
+
+/*!
+ \return true when enabled, false otherwise
+ \sa setEnabled, eventFilter()
+*/
+bool QwtPlotRescaler::isEnabled() const
+{
+ return d_data->isEnabled;
+}
+
+/*!
+ Change the rescale policy
+
+ \param policy Rescale policy
+ \sa rescalePolicy()
+*/
+void QwtPlotRescaler::setRescalePolicy( RescalePolicy policy )
+{
+ d_data->rescalePolicy = policy;
+}
+
+/*!
+ \return Rescale policy
+ \sa setRescalePolicy()
+*/
+QwtPlotRescaler::RescalePolicy QwtPlotRescaler::rescalePolicy() const
+{
+ return d_data->rescalePolicy;
+}
+
+/*!
+ Set the reference axis ( see RescalePolicy )
+
+ \param axis Axis index ( QwtPlot::Axis )
+ \sa referenceAxis()
+*/
+void QwtPlotRescaler::setReferenceAxis( int axis )
+{
+ d_data->referenceAxis = axis;
+}
+
+/*!
+ \return Reference axis ( see RescalePolicy )
+ \sa setReferenceAxis()
+*/
+int QwtPlotRescaler::referenceAxis() const
+{
+ return d_data->referenceAxis;
+}
+
+/*!
+ Set the direction in which all axis should be expanded
+
+ \param direction Direction
+ \sa expandingDirection()
+*/
+void QwtPlotRescaler::setExpandingDirection(
+ ExpandingDirection direction )
+{
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ setExpandingDirection( axis, direction );
+}
+
+/*!
+ Set the direction in which an axis should be expanded
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \param direction Direction
+ \sa expandingDirection()
+*/
+void QwtPlotRescaler::setExpandingDirection(
+ int axis, ExpandingDirection direction )
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->axisData[axis].expandingDirection = direction;
+}
+
+/*!
+ Return direction in which an axis should be expanded
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \sa setExpandingDirection()
+*/
+QwtPlotRescaler::ExpandingDirection
+QwtPlotRescaler::expandingDirection( int axis ) const
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ return d_data->axisData[axis].expandingDirection;
+
+ return ExpandBoth;
+}
+
+/*!
+ Set the aspect ratio between the scale of the reference axis
+ and the other scales. The default ratio is 1.0
+
+ \param ratio Aspect ratio
+ \sa aspectRatio()
+*/
+void QwtPlotRescaler::setAspectRatio( double ratio )
+{
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ setAspectRatio( axis, ratio );
+}
+
+/*!
+ Set the aspect ratio between the scale of the reference axis
+ and another scale. The default ratio is 1.0
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \param ratio Aspect ratio
+ \sa aspectRatio()
+*/
+void QwtPlotRescaler::setAspectRatio( int axis, double ratio )
+{
+ if ( ratio < 0.0 )
+ ratio = 0.0;
+
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->axisData[axis].aspectRatio = ratio;
+}
+
+/*!
+ Return aspect ratio between an axis and the reference axis.
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \sa setAspectRatio()
+*/
+double QwtPlotRescaler::aspectRatio( int axis ) const
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ return d_data->axisData[axis].aspectRatio;
+
+ return 0.0;
+}
+
+/*!
+ Set an interval hint for an axis
+
+ In Fitting mode, the hint is used as minimal interval
+ taht always needs to be displayed.
+
+ \param axis Axis, see QwtPlot::Axis
+ \param interval Axis
+ \sa intervalHint(), RescalePolicy
+*/
+void QwtPlotRescaler::setIntervalHint( int axis,
+ const QwtInterval &interval )
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ d_data->axisData[axis].intervalHint = interval;
+}
+
+/*!
+ \param axis Axis, see QwtPlot::Axis
+ \return Interval hint
+ \sa setIntervalHint(), RescalePolicy
+*/
+QwtInterval QwtPlotRescaler::intervalHint( int axis ) const
+{
+ if ( axis >= 0 && axis < QwtPlot::axisCnt )
+ return d_data->axisData[axis].intervalHint;
+
+ return QwtInterval();
+}
+
+//! \return plot canvas
+QwtPlotCanvas *QwtPlotRescaler::canvas()
+{
+ return qobject_cast<QwtPlotCanvas *>( parent() );
+}
+
+//! \return plot canvas
+const QwtPlotCanvas *QwtPlotRescaler::canvas() const
+{
+ return qobject_cast<const QwtPlotCanvas *>( parent() );
+}
+
+//! \return plot widget
+QwtPlot *QwtPlotRescaler::plot()
+{
+ QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+//! \return plot widget
+const QwtPlot *QwtPlotRescaler::plot() const
+{
+ const QwtPlotCanvas *w = canvas();
+ if ( w )
+ return w->plot();
+
+ return NULL;
+}
+
+//! Event filter for the plot canvas
+bool QwtPlotRescaler::eventFilter( QObject *object, QEvent *event )
+{
+ if ( object && object == canvas() )
+ {
+ switch ( event->type() )
+ {
+ case QEvent::Resize:
+ {
+ canvasResizeEvent( ( QResizeEvent * )event );
+ break;
+ }
+ case QEvent::PolishRequest:
+ {
+ rescale();
+ break;
+ }
+ default:;
+ }
+ }
+
+ return false;
+}
+
+/*!
+ Event handler for resize events of the plot canvas
+
+ \param event Resize event
+ \sa rescale()
+*/
+void QwtPlotRescaler::canvasResizeEvent( QResizeEvent* event )
+{
+ const int fw = 2 * canvas()->frameWidth();
+ const QSize newSize = event->size() - QSize( fw, fw );
+ const QSize oldSize = event->oldSize() - QSize( fw, fw );
+
+ rescale( oldSize, newSize );
+}
+
+//! Adjust the plot axes scales
+void QwtPlotRescaler::rescale() const
+{
+ const QSize size = canvas()->contentsRect().size();
+ rescale( size, size );
+}
+
+/*!
+ Adjust the plot axes scales
+
+ \param oldSize Previous size of the canvas
+ \param newSize New size of the canvas
+*/
+void QwtPlotRescaler::rescale(
+ const QSize &oldSize, const QSize &newSize ) const
+{
+ if ( newSize.isEmpty() )
+ return;
+
+ QwtInterval intervals[QwtPlot::axisCnt];
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ intervals[axis] = interval( axis );
+
+ const int refAxis = referenceAxis();
+ intervals[refAxis] = expandScale( refAxis, oldSize, newSize );
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( aspectRatio( axis ) > 0.0 && axis != refAxis )
+ intervals[axis] = syncScale( axis, intervals[refAxis], newSize );
+ }
+
+ updateScales( intervals );
+}
+
+/*!
+ Calculate the new scale interval of a plot axis
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \param oldSize Previous size of the canvas
+ \param newSize New size of the canvas
+
+ \return Calculated new interval for the axis
+*/
+QwtInterval QwtPlotRescaler::expandScale( int axis,
+ const QSize &oldSize, const QSize &newSize ) const
+{
+ const QwtInterval oldInterval = interval( axis );
+
+ QwtInterval expanded = oldInterval;
+ switch ( rescalePolicy() )
+ {
+ case Fixed:
+ {
+ break; // do nothing
+ }
+ case Expanding:
+ {
+ if ( !oldSize.isEmpty() )
+ {
+ double width = oldInterval.width();
+ if ( orientation( axis ) == Qt::Horizontal )
+ width *= double( newSize.width() ) / oldSize.width();
+ else
+ width *= double( newSize.height() ) / oldSize.height();
+
+ expanded = expandInterval( oldInterval,
+ width, expandingDirection( axis ) );
+ }
+ break;
+ }
+ case Fitting:
+ {
+ double dist = 0.0;
+ for ( int ax = 0; ax < QwtPlot::axisCnt; ax++ )
+ {
+ const double d = pixelDist( ax, newSize );
+ if ( d > dist )
+ dist = d;
+ }
+ if ( dist > 0.0 )
+ {
+ double width;
+ if ( orientation( axis ) == Qt::Horizontal )
+ width = newSize.width() * dist;
+ else
+ width = newSize.height() * dist;
+
+ expanded = expandInterval( intervalHint( axis ),
+ width, expandingDirection( axis ) );
+ }
+ break;
+ }
+ }
+
+ return expanded;
+}
+
+/*!
+ Synchronize an axis scale according to the scale of the reference axis
+
+ \param axis Axis index ( see QwtPlot::AxisId )
+ \param reference Interval of the reference axis
+ \param size Size of the canvas
+*/
+QwtInterval QwtPlotRescaler::syncScale( int axis,
+ const QwtInterval& reference, const QSize &size ) const
+{
+ double dist;
+ if ( orientation( referenceAxis() ) == Qt::Horizontal )
+ dist = reference.width() / size.width();
+ else
+ dist = reference.width() / size.height();
+
+ if ( orientation( axis ) == Qt::Horizontal )
+ dist *= size.width();
+ else
+ dist *= size.height();
+
+ dist /= aspectRatio( axis );
+
+ QwtInterval intv;
+ if ( rescalePolicy() == Fitting )
+ intv = intervalHint( axis );
+ else
+ intv = interval( axis );
+
+ intv = expandInterval( intv, dist, expandingDirection( axis ) );
+
+ return intv;
+}
+
+/*!
+ Return orientation of an axis
+ \param axis Axis index ( see QwtPlot::AxisId )
+*/
+Qt::Orientation QwtPlotRescaler::orientation( int axis ) const
+{
+ if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight )
+ return Qt::Vertical;
+
+ return Qt::Horizontal;
+}
+
+/*!
+ Return interval of an axis
+ \param axis Axis index ( see QwtPlot::AxisId )
+*/
+QwtInterval QwtPlotRescaler::interval( int axis ) const
+{
+ if ( axis < 0 || axis >= QwtPlot::axisCnt )
+ return QwtInterval();
+
+ const QwtPlot *plt = plot();
+
+ const double v1 = plt->axisScaleDiv( axis )->lowerBound();
+ const double v2 = plt->axisScaleDiv( axis )->upperBound();
+
+ return QwtInterval( v1, v2 ).normalized();
+}
+
+/*!
+ Expand the interval
+
+ \param interval Interval to be expanded
+ \param width Distance to be added to the interval
+ \param direction Direction of the expand operation
+
+ \return Expanded interval
+*/
+QwtInterval QwtPlotRescaler::expandInterval(
+ const QwtInterval &interval, double width,
+ ExpandingDirection direction ) const
+{
+ QwtInterval expanded = interval;
+
+ switch ( direction )
+ {
+ case ExpandUp:
+ expanded.setMinValue( interval.minValue() );
+ expanded.setMaxValue( interval.minValue() + width );
+ break;
+
+ case ExpandDown:
+ expanded.setMaxValue( interval.maxValue() );
+ expanded.setMinValue( interval.maxValue() - width );
+ break;
+
+ case ExpandBoth:
+ default:
+ expanded.setMinValue( interval.minValue() +
+ interval.width() / 2.0 - width / 2.0 );
+ expanded.setMaxValue( expanded.minValue() + width );
+ }
+ return expanded;
+}
+
+double QwtPlotRescaler::pixelDist( int axis, const QSize &size ) const
+{
+ const QwtInterval intv = intervalHint( axis );
+
+ double dist = 0.0;
+ if ( !intv.isNull() )
+ {
+ if ( axis == referenceAxis() )
+ dist = intv.width();
+ else
+ {
+ const double r = aspectRatio( axis );
+ if ( r > 0.0 )
+ dist = intv.width() * r;
+ }
+ }
+
+ if ( dist > 0.0 )
+ {
+ if ( orientation( axis ) == Qt::Horizontal )
+ dist /= size.width();
+ else
+ dist /= size.height();
+ }
+
+ return dist;
+}
+
+/*!
+ Update the axes scales
+
+ \param intervals Scale intervals
+*/
+void QwtPlotRescaler::updateScales(
+ QwtInterval intervals[QwtPlot::axisCnt] ) const
+{
+ if ( d_data->inReplot >= 5 )
+ {
+ return;
+ }
+
+ QwtPlot *plt = const_cast<QwtPlot *>( plot() );
+
+ const bool doReplot = plt->autoReplot();
+ plt->setAutoReplot( false );
+
+ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
+ {
+ if ( axis == referenceAxis() || aspectRatio( axis ) > 0.0 )
+ {
+ double v1 = intervals[axis].minValue();
+ double v2 = intervals[axis].maxValue();
+
+ if ( plt->axisScaleDiv( axis )->lowerBound() >
+ plt->axisScaleDiv( axis )->upperBound() )
+ {
+ qSwap( v1, v2 );
+ }
+
+ if ( d_data->inReplot >= 1 )
+ {
+ d_data->axisData[axis].scaleDiv = *plt->axisScaleDiv( axis );
+ }
+
+ if ( d_data->inReplot >= 2 )
+ {
+ QList<double> ticks[QwtScaleDiv::NTickTypes];
+ for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
+ ticks[i] = d_data->axisData[axis].scaleDiv.ticks( i );
+
+ plt->setAxisScaleDiv( axis, QwtScaleDiv( v1, v2, ticks ) );
+ }
+ else
+ {
+ plt->setAxisScale( axis, v1, v2 );
+ }
+ }
+ }
+
+ const bool immediatePaint =
+ plt->canvas()->testPaintAttribute( QwtPlotCanvas::ImmediatePaint );
+ plt->canvas()->setPaintAttribute( QwtPlotCanvas::ImmediatePaint, false );
+
+ plt->setAutoReplot( doReplot );
+
+ d_data->inReplot++;
+ plt->replot();
+ d_data->inReplot--;
+
+ plt->canvas()->setPaintAttribute(
+ QwtPlotCanvas::ImmediatePaint, immediatePaint );
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_rescaler.h b/src/libpcp_qwt/src/qwt_plot_rescaler.h
new file mode 100644
index 0000000..40cf3f9
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_rescaler.h
@@ -0,0 +1,143 @@
+/* -*- 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_PLOT_RESCALER_H
+#define QWT_PLOT_RESCALER_H 1
+
+#include "qwt_global.h"
+#include "qwt_interval.h"
+#include "qwt_plot.h"
+#include <qobject.h>
+
+class QwtPlotCanvas;
+class QwtPlot;
+class QResizeEvent;
+
+/*!
+ \brief QwtPlotRescaler takes care of fixed aspect ratios for plot scales
+
+ QwtPlotRescaler autoadjusts the axes of a QwtPlot according
+ to fixed aspect ratios.
+*/
+
+class QWT_EXPORT QwtPlotRescaler: public QObject
+{
+public:
+ /*!
+ The rescale policy defines how to rescale the reference axis and
+ their depending axes.
+
+ \sa ExpandingDirection, setIntervalHint()
+ */
+ enum RescalePolicy
+ {
+ /*!
+ The interval of the reference axis remains unchanged, when the
+ geometry of the canvas changes. All other axes
+ will be adjusted according to their aspect ratio.
+ */
+ Fixed,
+
+ /*!
+ The interval of the reference axis will be shrinked/expanded,
+ when the geometry of the canvas changes. All other axes
+ will be adjusted according to their aspect ratio.
+
+ The interval, that is represented by one pixel is fixed.
+
+ */
+ Expanding,
+
+ /*!
+ The intervals of the axes are calculated, so that all axes include
+ their interval hint.
+ */
+ Fitting
+ };
+
+ /*!
+ When rescalePolicy() is set to Expanding its direction depends
+ on ExpandingDirection
+ */
+ enum ExpandingDirection
+ {
+ //! The upper limit of the scale is adjusted
+ ExpandUp,
+
+ //! The lower limit of the scale is adjusted
+ ExpandDown,
+
+ //! Both limits of the scale are adjusted
+ ExpandBoth
+ };
+
+ explicit QwtPlotRescaler( QwtPlotCanvas *,
+ int referenceAxis = QwtPlot::xBottom,
+ RescalePolicy = Expanding );
+
+ virtual ~QwtPlotRescaler();
+
+ void setEnabled( bool );
+ bool isEnabled() const;
+
+ void setRescalePolicy( RescalePolicy );
+ RescalePolicy rescalePolicy() const;
+
+ void setExpandingDirection( ExpandingDirection );
+ void setExpandingDirection( int axis, ExpandingDirection );
+ ExpandingDirection expandingDirection( int axis ) const;
+
+ void setReferenceAxis( int axis );
+ int referenceAxis() const;
+
+ void setAspectRatio( double ratio );
+ void setAspectRatio( int axis, double ratio );
+ double aspectRatio( int axis ) const;
+
+ void setIntervalHint( int axis, const QwtInterval& );
+ QwtInterval intervalHint( int axis ) const;
+
+ QwtPlotCanvas *canvas();
+ const QwtPlotCanvas *canvas() const;
+
+ QwtPlot *plot();
+ const QwtPlot *plot() const;
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ void rescale() const;
+
+protected:
+ virtual void canvasResizeEvent( QResizeEvent * );
+
+ virtual void rescale( const QSize &oldSize, const QSize &newSize ) const;
+ virtual QwtInterval expandScale(
+ int axis, const QSize &oldSize, const QSize &newSize ) const;
+
+ virtual QwtInterval syncScale(
+ int axis, const QwtInterval& reference,
+ const QSize &size ) const;
+
+ virtual void updateScales(
+ QwtInterval intervals[QwtPlot::axisCnt] ) const;
+
+ Qt::Orientation orientation( int axis ) const;
+ QwtInterval interval( int axis ) const;
+ QwtInterval expandInterval( const QwtInterval &,
+ double width, ExpandingDirection ) const;
+
+private:
+ double pixelDist( int axis, const QSize & ) const;
+
+ class AxisData;
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_scaleitem.cpp b/src/libpcp_qwt/src/qwt_plot_scaleitem.cpp
new file mode 100644
index 0000000..212f5be
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_scaleitem.cpp
@@ -0,0 +1,445 @@
+/* -*- 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_plot_scaleitem.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_map.h"
+#include "qwt_interval.h"
+#include <qpalette.h>
+#include <qpainter.h>
+
+class QwtPlotScaleItem::PrivateData
+{
+public:
+ PrivateData():
+ position( 0.0 ),
+ borderDistance( -1 ),
+ scaleDivFromAxis( true ),
+ scaleDraw( new QwtScaleDraw() )
+ {
+ }
+
+ ~PrivateData()
+ {
+ delete scaleDraw;
+ }
+
+ void updateBorders( const QRectF &,
+ const QwtScaleMap &, const QwtScaleMap & );
+
+ QPalette palette;
+ QFont font;
+ double position;
+ int borderDistance;
+ bool scaleDivFromAxis;
+ QwtScaleDraw *scaleDraw;
+ QRectF canvasRectCache;
+};
+
+void QwtPlotScaleItem::PrivateData::updateBorders( const QRectF &canvasRect,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap )
+{
+ QwtInterval interval;
+ if ( scaleDraw->orientation() == Qt::Horizontal )
+ {
+ interval.setMinValue( xMap.invTransform( canvasRect.left() ) );
+ interval.setMaxValue( xMap.invTransform( canvasRect.right() - 1 ) );
+ }
+ else
+ {
+ interval.setMinValue( yMap.invTransform( canvasRect.bottom() - 1 ) );
+ interval.setMaxValue( yMap.invTransform( canvasRect.top() ) );
+ }
+
+ QwtScaleDiv scaleDiv = scaleDraw->scaleDiv();
+ scaleDiv.setInterval( interval );
+ scaleDraw->setScaleDiv( scaleDiv );
+}
+/*!
+ \brief Constructor for scale item at the position pos.
+
+ \param alignment In case of QwtScaleDraw::BottomScale or QwtScaleDraw::TopScale
+ the scale item is corresponding to the xAxis(),
+ otherwise it corresponds to the yAxis().
+
+ \param pos x or y position, depending on the corresponding axis.
+
+ \sa setPosition(), setAlignment()
+*/
+QwtPlotScaleItem::QwtPlotScaleItem(
+ QwtScaleDraw::Alignment alignment, const double pos ):
+ QwtPlotItem( QwtText( "Scale" ) )
+{
+ d_data = new PrivateData;
+ d_data->position = pos;
+ d_data->scaleDraw->setAlignment( alignment );
+
+ setZ( 11.0 );
+}
+
+//! Destructor
+QwtPlotScaleItem::~QwtPlotScaleItem()
+{
+ delete d_data;
+}
+
+//! \return QwtPlotItem::Rtti_PlotScale
+int QwtPlotScaleItem::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotScale;
+}
+
+/*!
+ \brief Assign a scale division
+
+ When assigning a scaleDiv the scale division won't be synchronized
+ with the corresponding axis anymore.
+
+ \param scaleDiv Scale division
+ \sa scaleDiv(), setScaleDivFromAxis(), isScaleDivFromAxis()
+*/
+void QwtPlotScaleItem::setScaleDiv( const QwtScaleDiv& scaleDiv )
+{
+ d_data->scaleDivFromAxis = false;
+ d_data->scaleDraw->setScaleDiv( scaleDiv );
+}
+
+//! \return Scale division
+const QwtScaleDiv& QwtPlotScaleItem::scaleDiv() const
+{
+ return d_data->scaleDraw->scaleDiv();
+}
+
+/*!
+ Enable/Disable the synchronization of the scale division with
+ the corresponding axis.
+
+ \param on true/false
+ \sa isScaleDivFromAxis()
+*/
+void QwtPlotScaleItem::setScaleDivFromAxis( bool on )
+{
+ if ( on != d_data->scaleDivFromAxis )
+ {
+ d_data->scaleDivFromAxis = on;
+ if ( on )
+ {
+ const QwtPlot *plt = plot();
+ if ( plt )
+ {
+ updateScaleDiv( *plt->axisScaleDiv( xAxis() ),
+ *plt->axisScaleDiv( yAxis() ) );
+ itemChanged();
+ }
+ }
+ }
+}
+
+/*!
+ \return True, if the synchronization of the scale division with
+ the corresponding axis is enabled.
+ \sa setScaleDiv(), setScaleDivFromAxis()
+*/
+bool QwtPlotScaleItem::isScaleDivFromAxis() const
+{
+ return d_data->scaleDivFromAxis;
+}
+
+/*!
+ Set the palette
+ \sa QwtAbstractScaleDraw::draw(), palette()
+*/
+void QwtPlotScaleItem::setPalette( const QPalette &palette )
+{
+ if ( palette != d_data->palette )
+ {
+ d_data->palette = palette;
+ itemChanged();
+ }
+}
+
+/*!
+ \return palette
+ \sa setPalette()
+*/
+QPalette QwtPlotScaleItem::palette() const
+{
+ return d_data->palette;
+}
+
+/*!
+ Change the tick label font
+ \sa font()
+*/
+void QwtPlotScaleItem::setFont( const QFont &font )
+{
+ if ( font != d_data->font )
+ {
+ d_data->font = font;
+ itemChanged();
+ }
+}
+
+/*!
+ \return tick label font
+ \sa setFont()
+*/
+QFont QwtPlotScaleItem::font() const
+{
+ return d_data->font;
+}
+
+/*!
+ \brief Set a scale draw
+
+ \param scaleDraw object responsible for drawing scales.
+
+ The main use case for replacing the default QwtScaleDraw is
+ to overload QwtAbstractScaleDraw::label, to replace or swallow
+ tick labels.
+
+ \sa scaleDraw()
+*/
+void QwtPlotScaleItem::setScaleDraw( QwtScaleDraw *scaleDraw )
+{
+ if ( scaleDraw == NULL )
+ return;
+
+ if ( scaleDraw != d_data->scaleDraw )
+ delete d_data->scaleDraw;
+
+ d_data->scaleDraw = scaleDraw;
+
+ const QwtPlot *plt = plot();
+ if ( plt )
+ {
+ updateScaleDiv( *plt->axisScaleDiv( xAxis() ),
+ *plt->axisScaleDiv( yAxis() ) );
+ }
+
+ itemChanged();
+}
+
+/*!
+ \return Scale draw
+ \sa setScaleDraw()
+*/
+const QwtScaleDraw *QwtPlotScaleItem::scaleDraw() const
+{
+ return d_data->scaleDraw;
+}
+
+/*!
+ \return Scale draw
+ \sa setScaleDraw()
+*/
+QwtScaleDraw *QwtPlotScaleItem::scaleDraw()
+{
+ return d_data->scaleDraw;
+}
+
+/*!
+ Change the position of the scale
+
+ The position is interpreted as y value for horizontal axes
+ and as x value for vertical axes.
+
+ The border distance is set to -1.
+
+ \param pos New position
+ \sa position(), setAlignment()
+*/
+void QwtPlotScaleItem::setPosition( double pos )
+{
+ if ( d_data->position != pos )
+ {
+ d_data->position = pos;
+ d_data->borderDistance = -1;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Position of the scale
+ \sa setPosition(), setAlignment()
+*/
+double QwtPlotScaleItem::position() const
+{
+ return d_data->position;
+}
+
+/*!
+ \brief Align the scale to the canvas
+
+ If distance is >= 0 the scale will be aligned to a
+ border of the contents rect of the canvas. If
+ alignment() is QwtScaleDraw::LeftScale, the scale will
+ be aligned to the right border, if it is QwtScaleDraw::TopScale
+ it will be aligned to the bottom (and vice versa),
+
+ If distance is < 0 the scale will be at the position().
+
+ \param distance Number of pixels between the canvas border and the
+ backbone of the scale.
+
+ \sa setPosition(), borderDistance()
+*/
+void QwtPlotScaleItem::setBorderDistance( int distance )
+{
+ if ( distance < 0 )
+ distance = -1;
+
+ if ( distance != d_data->borderDistance )
+ {
+ d_data->borderDistance = distance;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Distance from a canvas border
+ \sa setBorderDistance(), setPosition()
+*/
+int QwtPlotScaleItem::borderDistance() const
+{
+ return d_data->borderDistance;
+}
+
+/*!
+ Change the alignment of the scale
+
+ The alignment sets the orientation of the scale and the position of
+ the ticks:
+
+ - QwtScaleDraw::BottomScale: horizontal, ticks below
+ - QwtScaleDraw::TopScale: horizontal, ticks above
+ - QwtScaleDraw::LeftScale: vertical, ticks left
+ - QwtScaleDraw::RightScale: vertical, ticks right
+
+ For horizontal scales the position corresponds to QwtPlotItem::yAxis(),
+ otherwise to QwtPlotItem::xAxis().
+
+ \sa scaleDraw(), QwtScaleDraw::alignment(), setPosition()
+*/
+void QwtPlotScaleItem::setAlignment( QwtScaleDraw::Alignment alignment )
+{
+ QwtScaleDraw *sd = d_data->scaleDraw;
+ if ( sd->alignment() != alignment )
+ {
+ sd->setAlignment( alignment );
+ itemChanged();
+ }
+}
+
+/*!
+ \brief Draw the scale
+*/
+void QwtPlotScaleItem::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ if ( d_data->scaleDivFromAxis )
+ {
+ if ( canvasRect != d_data->canvasRectCache )
+ {
+ d_data->updateBorders( canvasRect, xMap, yMap );
+ d_data->canvasRectCache = canvasRect;
+ }
+ }
+
+ QPen pen = painter->pen();
+ pen.setStyle( Qt::SolidLine );
+ painter->setPen( pen );
+
+ QwtScaleDraw *sd = d_data->scaleDraw;
+ if ( sd->orientation() == Qt::Horizontal )
+ {
+ double y;
+ if ( d_data->borderDistance >= 0 )
+ {
+ if ( sd->alignment() == QwtScaleDraw::BottomScale )
+ y = canvasRect.top() + d_data->borderDistance;
+ else
+ {
+ y = canvasRect.bottom() - d_data->borderDistance;
+ }
+
+ }
+ else
+ {
+ y = yMap.transform( d_data->position );
+ }
+
+ if ( y < canvasRect.top() || y > canvasRect.bottom() )
+ return;
+
+ sd->move( canvasRect.left(), y );
+ sd->setLength( canvasRect.width() - 1 );
+ sd->setTransformation( xMap.transformation()->copy() );
+ }
+ else // == Qt::Vertical
+ {
+ double x;
+ if ( d_data->borderDistance >= 0 )
+ {
+ if ( sd->alignment() == QwtScaleDraw::RightScale )
+ x = canvasRect.left() + d_data->borderDistance;
+ else
+ {
+ x = canvasRect.right() - d_data->borderDistance;
+ }
+ }
+ else
+ {
+ x = xMap.transform( d_data->position );
+ }
+ if ( x < canvasRect.left() || x > canvasRect.right() )
+ return;
+
+ sd->move( x, canvasRect.top() );
+ sd->setLength( canvasRect.height() - 1 );
+ sd->setTransformation( yMap.transformation()->copy() );
+ }
+
+ painter->setFont( d_data->font );
+
+ sd->draw( painter, d_data->palette );
+}
+
+/*!
+ \brief Update the item to changes of the axes scale division
+
+ In case of isScaleDivFromAxis(), the scale draw is synchronized
+ to the correspond axis.
+
+ \param xScaleDiv Scale division of the x-axis
+ \param yScaleDiv Scale division of the y-axis
+
+ \sa QwtPlot::updateAxes()
+*/
+
+void QwtPlotScaleItem::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
+ const QwtScaleDiv& yScaleDiv )
+{
+ QwtScaleDraw *sd = d_data->scaleDraw;
+ if ( d_data->scaleDivFromAxis && sd )
+ {
+ sd->setScaleDiv(
+ sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv );
+
+ const QwtPlot *plt = plot();
+ if ( plt != NULL )
+ {
+ d_data->updateBorders( plt->canvas()->contentsRect(),
+ plt->canvasMap( xAxis() ), plt->canvasMap( yAxis() ) );
+ d_data->canvasRectCache = QRect();
+ }
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_scaleitem.h b/src/libpcp_qwt/src/qwt_plot_scaleitem.h
new file mode 100644
index 0000000..ead67a3
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_scaleitem.h
@@ -0,0 +1,94 @@
+/* -*- 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_PLOT_SCALE_ITEM_H
+#define QWT_PLOT_SCALE_ITEM_H
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include "qwt_scale_draw.h"
+
+class QPalette;
+
+/*!
+ \brief A class which draws a scale inside the plot canvas
+
+ QwtPlotScaleItem can be used to draw an axis inside the plot canvas.
+ It might by synchronized to one of the axis of the plot, but can
+ also display its own ticks and labels.
+
+ It is allowed to synchronize the scale item with a disabled axis.
+ In plots with vertical and horizontal scale items, it might be
+ necessary to remove ticks at the intersections, by overloading
+ updateScaleDiv().
+
+ The scale might be at a specific position (f.e 0.0) or it might be
+ aligned to a canvas border.
+
+ \par Example
+ The following example shows how to replace the left axis, by a scale item
+ at the x position 0.0.
+ \verbatim
+QwtPlotScaleItem *scaleItem =
+ new QwtPlotScaleItem(QwtScaleDraw::RightScale, 0.0);
+scaleItem->setFont(plot->axisWidget(QwtPlot::yLeft)->font());
+scaleItem->attach(plot);
+
+plot->enableAxis(QwtPlot::yLeft, false);
+\endverbatim
+*/
+
+class QWT_EXPORT QwtPlotScaleItem: public QwtPlotItem
+{
+public:
+ explicit QwtPlotScaleItem(
+ QwtScaleDraw::Alignment = QwtScaleDraw::BottomScale,
+ const double pos = 0.0 );
+
+ virtual ~QwtPlotScaleItem();
+
+ virtual int rtti() const;
+
+ void setScaleDiv( const QwtScaleDiv& );
+ const QwtScaleDiv& scaleDiv() const;
+
+ void setScaleDivFromAxis( bool on );
+ bool isScaleDivFromAxis() const;
+
+ void setPalette( const QPalette & );
+ QPalette palette() const;
+
+ void setFont( const QFont& );
+ QFont font() const;
+
+ void setScaleDraw( QwtScaleDraw * );
+
+ const QwtScaleDraw *scaleDraw() const;
+ QwtScaleDraw *scaleDraw();
+
+ void setPosition( double pos );
+ double position() const;
+
+ void setBorderDistance( int numPixels );
+ int borderDistance() const;
+
+ void setAlignment( QwtScaleDraw::Alignment );
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &rect ) const;
+
+ virtual void updateScaleDiv( const QwtScaleDiv &, const QwtScaleDiv & );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_seriesitem.cpp b/src/libpcp_qwt/src/qwt_plot_seriesitem.cpp
new file mode 100644
index 0000000..c4cdd53
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_seriesitem.cpp
@@ -0,0 +1,90 @@
+/* -*- 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_plot_seriesitem.h"
+
+class QwtPlotAbstractSeriesItem::PrivateData
+{
+public:
+ PrivateData():
+ orientation( Qt::Vertical )
+ {
+ }
+
+ Qt::Orientation orientation;
+};
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotAbstractSeriesItem::QwtPlotAbstractSeriesItem( const QwtText &title ):
+ QwtPlotItem( title )
+{
+ d_data = new PrivateData();
+}
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotAbstractSeriesItem::QwtPlotAbstractSeriesItem( const QString &title ):
+ QwtPlotItem( QwtText( title ) )
+{
+ d_data = new PrivateData();
+}
+
+//! Destructor
+QwtPlotAbstractSeriesItem::~QwtPlotAbstractSeriesItem()
+{
+ delete d_data;
+}
+
+/*!
+ Set the orientation of the item.
+
+ The orientation() might be used in specific way by a plot item.
+ F.e. a QwtPlotCurve uses it to identify how to display the curve
+ int QwtPlotCurve::Steps or QwtPlotCurve::Sticks style.
+
+ \sa orientation()
+*/
+void QwtPlotAbstractSeriesItem::setOrientation( Qt::Orientation orientation )
+{
+ if ( d_data->orientation != orientation )
+ {
+ d_data->orientation = orientation;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Orientation of the plot item
+ \sa setOrientation()
+*/
+Qt::Orientation QwtPlotAbstractSeriesItem::orientation() const
+{
+ return d_data->orientation;
+}
+
+/*!
+ \brief Draw the complete series
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+*/
+void QwtPlotAbstractSeriesItem::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ drawSeries( painter, xMap, yMap, canvasRect, 0, -1 );
+}
+
diff --git a/src/libpcp_qwt/src/qwt_plot_seriesitem.h b/src/libpcp_qwt/src/qwt_plot_seriesitem.h
new file mode 100644
index 0000000..d6c2d1f
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_seriesitem.h
@@ -0,0 +1,206 @@
+/* -*- 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_PLOT_SERIES_ITEM_H
+#define QWT_PLOT_SERIES_ITEM_H
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include "qwt_scale_div.h"
+#include "qwt_series_data.h"
+
+/*!
+ \brief Base class for plot items representing a series of samples
+*/
+class QWT_EXPORT QwtPlotAbstractSeriesItem: public QwtPlotItem
+{
+public:
+ explicit QwtPlotAbstractSeriesItem( const QString &title = QString::null );
+ explicit QwtPlotAbstractSeriesItem( const QwtText &title );
+
+ virtual ~QwtPlotAbstractSeriesItem();
+
+ void setOrientation( Qt::Orientation );
+ Qt::Orientation orientation() const;
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF & ) const;
+
+ /*!
+ Draw a subset of the samples
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first point to be painted
+ \param to Index of the last point to be painted. If to < 0 the
+ curve will be painted to its last point.
+ */
+ virtual void drawSeries( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const = 0;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+/*!
+ \brief Class template for plot items representing a series of samples
+*/
+template <typename T>
+class QwtPlotSeriesItem: public QwtPlotAbstractSeriesItem
+{
+public:
+ explicit QwtPlotSeriesItem<T>( const QString &title = QString::null );
+ explicit QwtPlotSeriesItem<T>( const QwtText &title );
+
+ virtual ~QwtPlotSeriesItem<T>();
+
+ void setData( QwtSeriesData<T> * );
+
+ QwtSeriesData<T> *data();
+ const QwtSeriesData<T> *data() const;
+
+ size_t dataSize() const;
+ T sample( int index ) const;
+
+ virtual QRectF boundingRect() const;
+ virtual void updateScaleDiv( const QwtScaleDiv &,
+ const QwtScaleDiv & );
+
+protected:
+ //! Series
+ QwtSeriesData<T> *d_series;
+};
+
+/*!
+ Constructor
+ \param title Title of the series item
+*/
+template <typename T>
+QwtPlotSeriesItem<T>::QwtPlotSeriesItem( const QString &title ):
+ QwtPlotAbstractSeriesItem( QwtText( title ) ),
+ d_series( NULL )
+{
+}
+
+/*!
+ Constructor
+ \param title Title of the series item
+*/
+template <typename T>
+QwtPlotSeriesItem<T>::QwtPlotSeriesItem( const QwtText &title ):
+ QwtPlotAbstractSeriesItem( title ),
+ d_series( NULL )
+{
+}
+
+//! Destructor
+template <typename T>
+QwtPlotSeriesItem<T>::~QwtPlotSeriesItem()
+{
+ delete d_series;
+}
+
+//! \return the the curve data
+template <typename T>
+inline QwtSeriesData<T> *QwtPlotSeriesItem<T>::data()
+{
+ return d_series;
+}
+
+//! \return the the curve data
+template <typename T>
+inline const QwtSeriesData<T> *QwtPlotSeriesItem<T>::data() const
+{
+ return d_series;
+}
+
+/*!
+ \param index Index
+ \return Sample at position index
+*/
+template <typename T>
+inline T QwtPlotSeriesItem<T>::sample( int index ) const
+{
+ return d_series ? d_series->sample( index ) : T();
+}
+
+/*!
+ Assign a series of samples
+
+ \param data Data
+ \warning The item takes ownership of the data object, deleting
+ it when its not used anymore.
+*/
+template <typename T>
+void QwtPlotSeriesItem<T>::setData( QwtSeriesData<T> *data )
+{
+ if ( d_series != data )
+ {
+ delete d_series;
+ d_series = data;
+ itemChanged();
+ }
+}
+
+/*!
+ Return the size of the data arrays
+ \sa setData()
+*/
+template <typename T>
+size_t QwtPlotSeriesItem<T>::dataSize() const
+{
+ if ( d_series == NULL )
+ return 0;
+
+ return d_series->size();
+}
+
+/*!
+ \return Bounding rectangle of the data.
+ If there is no bounding rect, like for empty data the rectangle is invalid.
+
+ \sa QwtSeriesData<T>::boundingRect(), QRectF::isValid()
+*/
+template <typename T>
+QRectF QwtPlotSeriesItem<T>::boundingRect() const
+{
+ if ( d_series == NULL )
+ return QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid
+
+ return d_series->boundingRect();
+}
+
+/*!
+ Update the rect of interest according to the current scale ranges
+
+ \param xScaleDiv Scale division of the x-axis
+ \param yScaleDiv Scale division of the y-axis
+
+ \sa QwtSeriesData<T>::setRectOfInterest()
+*/
+template <typename T>
+void QwtPlotSeriesItem<T>::updateScaleDiv(
+ const QwtScaleDiv &xScaleDiv, const QwtScaleDiv &yScaleDiv )
+{
+ if ( d_series )
+ {
+ const QRectF rect = QRectF(
+ xScaleDiv.lowerBound(), yScaleDiv.lowerBound(),
+ xScaleDiv.range(), yScaleDiv.range() );
+
+ d_series->setRectOfInterest( rect );
+ }
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_spectrocurve.cpp b/src/libpcp_qwt/src/qwt_plot_spectrocurve.cpp
new file mode 100644
index 0000000..5df254d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_spectrocurve.cpp
@@ -0,0 +1,300 @@
+/* -*- 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_plot_spectrocurve.h"
+#include "qwt_color_map.h"
+#include "qwt_scale_map.h"
+#include "qwt_painter.h"
+#include <qpainter.h>
+
+class QwtPlotSpectroCurve::PrivateData
+{
+public:
+ PrivateData():
+ colorRange( 0.0, 1000.0 ),
+ penWidth(0.0),
+ paintAttributes( QwtPlotSpectroCurve::ClipPoints )
+ {
+ colorMap = new QwtLinearColorMap();
+ }
+
+ ~PrivateData()
+ {
+ delete colorMap;
+ }
+
+ QwtColorMap *colorMap;
+ QwtInterval colorRange;
+ QVector<QRgb> colorTable;
+ double penWidth;
+ QwtPlotSpectroCurve::PaintAttributes paintAttributes;
+};
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QwtText &title ):
+ QwtPlotSeriesItem<QwtPoint3D>( title )
+{
+ init();
+}
+
+/*!
+ Constructor
+ \param title Title of the curve
+*/
+QwtPlotSpectroCurve::QwtPlotSpectroCurve( const QString &title ):
+ QwtPlotSeriesItem<QwtPoint3D>( QwtText( title ) )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotSpectroCurve::~QwtPlotSpectroCurve()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Initialize data members
+*/
+void QwtPlotSpectroCurve::init()
+{
+ setItemAttribute( QwtPlotItem::Legend );
+ setItemAttribute( QwtPlotItem::AutoScale );
+
+ d_data = new PrivateData;
+ d_series = new QwtPoint3DSeriesData();
+
+ setZ( 20.0 );
+}
+
+//! \return QwtPlotItem::Rtti_PlotSpectroCurve
+int QwtPlotSpectroCurve::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotSpectroCurve;
+}
+
+/*!
+ Specify an attribute how to draw the curve
+
+ \param attribute Paint attribute
+ \param on On/Off
+ /sa PaintAttribute, testPaintAttribute()
+*/
+void QwtPlotSpectroCurve::setPaintAttribute( PaintAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+}
+
+/*!
+ \brief Return the current paint attributes
+ \sa PaintAttribute, setPaintAttribute()
+*/
+bool QwtPlotSpectroCurve::testPaintAttribute( PaintAttribute attribute ) const
+{
+ return ( d_data->paintAttributes & attribute );
+}
+
+/*!
+ Initialize data with an array of samples.
+ \param samples Vector of points
+*/
+void QwtPlotSpectroCurve::setSamples( const QVector<QwtPoint3D> &samples )
+{
+ delete d_series;
+ d_series = new QwtPoint3DSeriesData( samples );
+ itemChanged();
+}
+
+/*!
+ Change the color map
+
+ Often it is useful to display the mapping between intensities and
+ colors as an additional plot axis, showing a color bar.
+
+ \param colorMap Color Map
+
+ \sa colorMap(), setColorRange(), QwtColorMap::color(),
+ QwtScaleWidget::setColorBarEnabled(), QwtScaleWidget::setColorMap()
+*/
+void QwtPlotSpectroCurve::setColorMap( QwtColorMap *colorMap )
+{
+ if ( colorMap != d_data->colorMap )
+ {
+ delete d_data->colorMap;
+ d_data->colorMap = colorMap;
+ }
+
+ itemChanged();
+}
+
+/*!
+ \return Color Map used for mapping the intensity values to colors
+ \sa setColorMap(), setColorRange(), QwtColorMap::color()
+*/
+const QwtColorMap *QwtPlotSpectroCurve::colorMap() const
+{
+ return d_data->colorMap;
+}
+
+/*!
+ Set the value interval, that corresponds to the color map
+
+ \param interval interval.minValue() corresponds to 0.0,
+ interval.maxValue() to 1.0 on the color map.
+
+ \sa colorRange(), setColorMap(), QwtColorMap::color()
+*/
+void QwtPlotSpectroCurve::setColorRange( const QwtInterval &interval )
+{
+ if ( interval != d_data->colorRange )
+ {
+ d_data->colorRange = interval;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Value interval, that corresponds to the color map
+ \sa setColorRange(), setColorMap(), QwtColorMap::color()
+*/
+QwtInterval &QwtPlotSpectroCurve::colorRange() const
+{
+ return d_data->colorRange;
+}
+
+/*!
+ Assign a pen width
+
+ \param penWidth New pen width
+ \sa penWidth()
+*/
+void QwtPlotSpectroCurve::setPenWidth(double penWidth)
+{
+ if ( penWidth < 0.0 )
+ penWidth = 0.0;
+
+ if ( d_data->penWidth != penWidth )
+ {
+ d_data->penWidth = penWidth;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Pen width used to draw a dot
+ \sa setPenWidth()
+*/
+double QwtPlotSpectroCurve::penWidth() const
+{
+ return d_data->penWidth;
+}
+
+/*!
+ Draw a subset of the points
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ series will be painted to its last sample.
+
+ \sa drawDots()
+*/
+void QwtPlotSpectroCurve::drawSeries( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ if ( !painter || dataSize() <= 0 )
+ return;
+
+ if ( to < 0 )
+ to = dataSize() - 1;
+
+ if ( from < 0 )
+ from = 0;
+
+ if ( from > to )
+ return;
+
+ drawDots( painter, xMap, yMap, canvasRect, from, to );
+}
+
+/*!
+ Draw a subset of the points
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas
+ \param from Index of the first sample to be painted
+ \param to Index of the last sample to be painted. If to < 0 the
+ series will be painted to its last sample.
+
+ \sa drawSeries()
+*/
+void QwtPlotSpectroCurve::drawDots( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const
+{
+ if ( !d_data->colorRange.isValid() )
+ return;
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ const QwtColorMap::Format format = d_data->colorMap->format();
+ if ( format == QwtColorMap::Indexed )
+ d_data->colorTable = d_data->colorMap->colorTable( d_data->colorRange );
+
+ for ( int i = from; i <= to; i++ )
+ {
+ const QwtPoint3D sample = d_series->sample( i );
+
+ double xi = xMap.transform( sample.x() );
+ double yi = yMap.transform( sample.y() );
+ if ( doAlign )
+ {
+ xi = qRound( xi );
+ yi = qRound( yi );
+ }
+
+ if ( d_data->paintAttributes & QwtPlotSpectroCurve::ClipPoints )
+ {
+ if ( !canvasRect.contains( xi, yi ) )
+ continue;
+ }
+
+ if ( format == QwtColorMap::RGB )
+ {
+ const QRgb rgb = d_data->colorMap->rgb(
+ d_data->colorRange, sample.z() );
+
+ painter->setPen( QPen( QColor( rgb ), d_data->penWidth ) );
+ }
+ else
+ {
+ const unsigned char index = d_data->colorMap->colorIndex(
+ d_data->colorRange, sample.z() );
+
+ painter->setPen( QPen( QColor( d_data->colorTable[index] ),
+ d_data->penWidth ) );
+ }
+
+ QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
+ }
+
+ d_data->colorTable.clear();
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_spectrocurve.h b/src/libpcp_qwt/src/qwt_plot_spectrocurve.h
new file mode 100644
index 0000000..93caa17
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_spectrocurve.h
@@ -0,0 +1,76 @@
+/* -*- 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_PLOT_CURVE_3D_H
+#define QWT_PLOT_CURVE_3D_H
+
+#include "qwt_global.h"
+#include "qwt_plot_seriesitem.h"
+#include "qwt_series_data.h"
+
+class QwtSymbol;
+class QwtColorMap;
+
+/*!
+ \brief Curve that displays 3D points as dots, where the z coordinate is
+ mapped to a color.
+*/
+class QWT_EXPORT QwtPlotSpectroCurve: public QwtPlotSeriesItem<QwtPoint3D>
+{
+public:
+ //! Paint attributes
+ enum PaintAttribute
+ {
+ //! Clip points outside the canvas rectangle
+ ClipPoints = 1
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ explicit QwtPlotSpectroCurve( const QString &title = QString::null );
+ explicit QwtPlotSpectroCurve( const QwtText &title );
+
+ virtual ~QwtPlotSpectroCurve();
+
+ virtual int rtti() const;
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ void setSamples( const QVector<QwtPoint3D> & );
+
+ void setColorMap( QwtColorMap * );
+ const QwtColorMap *colorMap() const;
+
+ void setColorRange( const QwtInterval & );
+ QwtInterval & colorRange() const;
+
+ virtual void drawSeries( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+ void setPenWidth(double width);
+ double penWidth() const;
+
+protected:
+ virtual void drawDots( QPainter *,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect, int from, int to ) const;
+
+private:
+ void init();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotSpectroCurve::PaintAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_spectrogram.cpp b/src/libpcp_qwt/src/qwt_plot_spectrogram.cpp
new file mode 100644
index 0000000..0a0b694
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_spectrogram.cpp
@@ -0,0 +1,663 @@
+/* -*- 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_plot_spectrogram.h"
+#include "qwt_painter.h"
+#include "qwt_interval.h"
+#include "qwt_scale_map.h"
+#include "qwt_color_map.h"
+#include <qimage.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <qmath.h>
+#include <qalgorithms.h>
+#if QT_VERSION >= 0x040400
+#include <qthread.h>
+#include <qfuture.h>
+#include <qtconcurrentrun.h>
+#endif
+
+class QwtPlotSpectrogram::PrivateData
+{
+public:
+ PrivateData():
+ data( NULL ),
+ renderThreadCount( 1 )
+ {
+ colorMap = new QwtLinearColorMap();
+ displayMode = ImageMode;
+
+ conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel;
+ conrecFlags |= QwtRasterData::IgnoreOutOfRange;
+ }
+ ~PrivateData()
+ {
+ delete data;
+ delete colorMap;
+ }
+
+ QwtRasterData *data;
+ QwtColorMap *colorMap;
+ DisplayModes displayMode;
+
+ uint renderThreadCount;
+
+ QList<double> contourLevels;
+ QPen defaultContourPen;
+ QwtRasterData::ConrecFlags conrecFlags;
+};
+
+/*!
+ Sets the following item attributes:
+ - QwtPlotItem::AutoScale: true
+ - QwtPlotItem::Legend: false
+
+ The z value is initialized by 8.0.
+
+ \param title Title
+
+ \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ()
+*/
+QwtPlotSpectrogram::QwtPlotSpectrogram( const QString &title ):
+ QwtPlotRasterItem( title )
+{
+ d_data = new PrivateData();
+
+ setItemAttribute( QwtPlotItem::AutoScale, true );
+ setItemAttribute( QwtPlotItem::Legend, false );
+
+ setZ( 8.0 );
+}
+
+//! Destructor
+QwtPlotSpectrogram::~QwtPlotSpectrogram()
+{
+ delete d_data;
+}
+
+//! \return QwtPlotItem::Rtti_PlotSpectrogram
+int QwtPlotSpectrogram::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotSpectrogram;
+}
+
+/*!
+ The display mode controls how the raster data will be represented.
+
+ \param mode Display mode
+ \param on On/Off
+
+ The default setting enables ImageMode.
+
+ \sa DisplayMode, displayMode()
+*/
+void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on )
+{
+ if ( on != bool( mode & d_data->displayMode ) )
+ {
+ if ( on )
+ d_data->displayMode |= mode;
+ else
+ d_data->displayMode &= ~mode;
+ }
+
+ itemChanged();
+}
+
+/*!
+ The display mode controls how the raster data will be represented.
+
+ \param mode Display mode
+ \return true if mode is enabled
+*/
+bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const
+{
+ return ( d_data->displayMode & mode );
+}
+
+/*!
+ Rendering an image from the raster data can often be done
+ parallel on a multicore system.
+
+ \param numThreads Number of threads to be used for rendering.
+ If numThreads is set to 0, the system specific
+ ideal thread count is used.
+
+ The default thread count is 1 ( = no additional threads )
+
+ \warning Rendering in multiple threads is only supported for Qt >= 4.4
+ \sa renderThreadCount(), renderImage(), renderTile()
+*/
+void QwtPlotSpectrogram::setRenderThreadCount( uint numThreads )
+{
+ d_data->renderThreadCount = numThreads;
+}
+
+/*!
+ \return Number of threads to be used for rendering.
+ If numThreads is set to 0, the system specific
+ ideal thread count is used.
+
+ \warning Rendering in multiple threads is only supported for Qt >= 4.4
+ \sa setRenderThreadCount(), renderImage(), renderTile()
+*/
+uint QwtPlotSpectrogram::renderThreadCount() const
+{
+ return d_data->renderThreadCount;
+}
+
+/*!
+ Change the color map
+
+ Often it is useful to display the mapping between intensities and
+ colors as an additional plot axis, showing a color bar.
+
+ \param colorMap Color Map
+
+ \sa colorMap(), QwtScaleWidget::setColorBarEnabled(),
+ QwtScaleWidget::setColorMap()
+*/
+void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap )
+{
+ if ( d_data->colorMap != colorMap )
+ {
+ delete d_data->colorMap;
+ d_data->colorMap = colorMap;
+ }
+
+ invalidateCache();
+ itemChanged();
+}
+
+/*!
+ \return Color Map used for mapping the intensity values to colors
+ \sa setColorMap()
+*/
+const QwtColorMap *QwtPlotSpectrogram::colorMap() const
+{
+ return d_data->colorMap;
+}
+
+/*!
+ \brief Set the default pen for the contour lines
+
+ If the spectrogram has a valid default contour pen
+ a contour line is painted using the default contour pen.
+ Otherwise (pen.style() == Qt::NoPen) the pen is calculated
+ for each contour level using contourPen().
+
+ \sa defaultContourPen(), contourPen()
+*/
+void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen )
+{
+ if ( pen != d_data->defaultContourPen )
+ {
+ d_data->defaultContourPen = pen;
+ itemChanged();
+ }
+}
+
+/*!
+ \return Default contour pen
+ \sa setDefaultContourPen()
+*/
+QPen QwtPlotSpectrogram::defaultContourPen() const
+{
+ return d_data->defaultContourPen;
+}
+
+/*!
+ \brief Calculate the pen for a contour line
+
+ The color of the pen is the color for level calculated by the color map
+
+ \param level Contour level
+ \return Pen for the contour line
+ \note contourPen is only used if defaultContourPen().style() == Qt::NoPen
+
+ \sa setDefaultContourPen(), setColorMap(), setContourLevels()
+*/
+QPen QwtPlotSpectrogram::contourPen( double level ) const
+{
+ if ( d_data->data == NULL || d_data->colorMap == NULL )
+ return QPen();
+
+ const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis);
+ const QColor c( d_data->colorMap->rgb( intensityRange, level ) );
+
+ return QPen( c );
+}
+
+/*!
+ Modify an attribute of the CONREC algorithm, used to calculate
+ the contour lines.
+
+ \param flag CONREC flag
+ \param on On/Off
+
+ \sa testConrecFlag(), renderContourLines(),
+ QwtRasterData::contourLines()
+*/
+void QwtPlotSpectrogram::setConrecFlag(
+ QwtRasterData::ConrecFlag flag, bool on )
+{
+ if ( bool( d_data->conrecFlags & flag ) == on )
+ return;
+
+ if ( on )
+ d_data->conrecFlags |= flag;
+ else
+ d_data->conrecFlags &= ~flag;
+
+ itemChanged();
+}
+
+/*!
+ Test an attribute of the CONREC algorithm, used to calculate
+ the contour lines.
+
+ \param flag CONREC flag
+ \return true, is enabled
+
+ \sa setConrecClag(), renderContourLines(),
+ QwtRasterData::contourLines()
+*/
+bool QwtPlotSpectrogram::testConrecFlag(
+ QwtRasterData::ConrecFlag flag ) const
+{
+ return d_data->conrecFlags & flag;
+}
+
+/*!
+ Set the levels of the contour lines
+
+ \param levels Values of the contour levels
+ \sa contourLevels(), renderContourLines(),
+ QwtRasterData::contourLines()
+
+ \note contourLevels returns the same levels but sorted.
+*/
+void QwtPlotSpectrogram::setContourLevels( const QList<double> &levels )
+{
+ d_data->contourLevels = levels;
+ qSort( d_data->contourLevels );
+ itemChanged();
+}
+
+/*!
+ \brief Return the levels of the contour lines.
+
+ The levels are sorted in increasing order.
+
+ \sa contourLevels(), renderContourLines(),
+ QwtRasterData::contourLines()
+*/
+QList<double> QwtPlotSpectrogram::contourLevels() const
+{
+ return d_data->contourLevels;
+}
+
+/*!
+ Set the data to be displayed
+
+ \param data Spectrogram Data
+ \sa data()
+*/
+void QwtPlotSpectrogram::setData( QwtRasterData *data )
+{
+ if ( data != d_data->data )
+ {
+ delete d_data->data;
+ d_data->data = data;
+
+ invalidateCache();
+ itemChanged();
+ }
+}
+
+/*!
+ \return Spectrogram data
+ \sa setData()
+*/
+const QwtRasterData *QwtPlotSpectrogram::data() const
+{
+ return d_data->data;
+}
+
+/*!
+ \return Spectrogram data
+ \sa setData()
+*/
+QwtRasterData *QwtPlotSpectrogram::data()
+{
+ return d_data->data;
+}
+
+/*!
+ \return Bounding interval for an axis
+
+ The default implementation returns the interval of the
+ associated raster data object.
+
+ \param axis X, Y, or Z axis
+ \sa QwtRasterData::interval()
+*/
+QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const
+{
+ if ( d_data->data == NULL )
+ return QwtInterval();
+
+ return d_data->data->interval( axis );
+}
+
+/*!
+ \brief Pixel hint
+
+ The geometry of a pixel is used to calculated the resolution and
+ alignment of the rendered image.
+
+ The default implementation returns data()->pixelHint( rect );
+
+ \param area In most implementations the resolution of the data doesn't
+ depend on the requested area.
+
+ \return Bounding rectangle of a pixel
+
+ \sa QwtPlotRasterItem::pixelHint(), QwtRasterData::pixelHint(),
+ render(), renderImage()
+*/
+QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
+{
+ if ( d_data->data == NULL )
+ return QRectF();
+
+ return d_data->data->pixelHint( area );
+}
+
+/*!
+ \brief Render an image from data and color map.
+
+ For each pixel of rect the value is mapped into a color.
+
+ \param xMap X-Scale Map
+ \param yMap Y-Scale Map
+ \param area Requested area for the image in scale coordinates
+ \param imageSize Size of the requested image
+
+ \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending
+ on the color map.
+
+ \sa QwtRasterData::value(), QwtColorMap::rgb(),
+ QwtColorMap::colorIndex()
+*/
+QImage QwtPlotSpectrogram::renderImage(
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &area, const QSize &imageSize ) const
+{
+ if ( imageSize.isEmpty() || d_data->data == NULL
+ || d_data->colorMap == NULL )
+ {
+ return QImage();
+ }
+
+ const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
+ if ( !intensityRange.isValid() )
+ return QImage();
+
+ QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
+ ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
+
+ QImage image( imageSize, format );
+
+ if ( d_data->colorMap->format() == QwtColorMap::Indexed )
+ image.setColorTable( d_data->colorMap->colorTable( intensityRange ) );
+
+ d_data->data->initRaster( area, image.size() );
+
+#if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE)
+ uint numThreads = d_data->renderThreadCount;
+
+ if ( numThreads <= 0 )
+ numThreads = QThread::idealThreadCount();
+
+ if ( numThreads <= 0 )
+ numThreads = 1;
+
+ const int numRows = imageSize.height() / numThreads;
+
+ QList< QFuture<void> > futures;
+ for ( uint i = 0; i < numThreads; i++ )
+ {
+ QRect tile( 0, i * numRows, image.width(), numRows );
+ if ( i == numThreads - 1 )
+ {
+ tile.setHeight( image.height() - i * numRows );
+ renderTile( xMap, yMap, tile, &image );
+ }
+ else
+ {
+ futures += QtConcurrent::run(
+ this, &QwtPlotSpectrogram::renderTile,
+ xMap, yMap, tile, &image );
+ }
+ }
+ for ( int i = 0; i < futures.size(); i++ )
+ futures[i].waitForFinished();
+
+#else // QT_VERSION < 0x040400
+ const QRect tile( 0, 0, image.width(), image.height() );
+ renderTile( xMap, yMap, tile, &image );
+#endif
+
+ d_data->data->discardRaster();
+
+ return image;
+}
+
+/*!
+ \brief Render a tile of an image.
+
+ Rendering in tiles can be used to composite an image in parallel
+ threads.
+
+ \param xMap X-Scale Map
+ \param yMap Y-Scale Map
+ \param tile Geometry of the tile in image coordinates
+ \param image Image to be rendered
+*/
+void QwtPlotSpectrogram::renderTile(
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRect &tile, QImage *image ) const
+{
+ const QwtInterval range = d_data->data->interval( Qt::ZAxis );
+ if ( !range.isValid() )
+ return;
+
+ if ( d_data->colorMap->format() == QwtColorMap::RGB )
+ {
+ for ( int y = tile.top(); y <= tile.bottom(); y++ )
+ {
+ const double ty = yMap.invTransform( y );
+
+ QRgb *line = ( QRgb * )image->scanLine( y );
+ line += tile.left();
+
+ for ( int x = tile.left(); x <= tile.right(); x++ )
+ {
+ const double tx = xMap.invTransform( x );
+
+ *line++ = d_data->colorMap->rgb( range,
+ d_data->data->value( tx, ty ) );
+ }
+ }
+ }
+ else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
+ {
+ for ( int y = tile.top(); y <= tile.bottom(); y++ )
+ {
+ const double ty = yMap.invTransform( y );
+
+ unsigned char *line = image->scanLine( y );
+ line += tile.left();
+
+ for ( int x = tile.left(); x <= tile.right(); x++ )
+ {
+ const double tx = xMap.invTransform( x );
+
+ *line++ = d_data->colorMap->colorIndex( range,
+ d_data->data->value( tx, ty ) );
+ }
+ }
+ }
+}
+
+/*!
+ \brief Return the raster to be used by the CONREC contour algorithm.
+
+ A larger size will improve the precisision of the CONREC algorithm,
+ but will slow down the time that is needed to calculate the lines.
+
+ The default implementation returns rect.size() / 2 bounded to
+ the resolution depending on pixelSize().
+
+ \param area Rect, where to calculate the contour lines
+ \param rect Rect in pixel coordinates, where to paint the contour lines
+ \return Raster to be used by the CONREC contour algorithm.
+
+ \note The size will be bounded to rect.size().
+
+ \sa drawContourLines(), QwtRasterData::contourLines()
+*/
+QSize QwtPlotSpectrogram::contourRasterSize(
+ const QRectF &area, const QRect &rect ) const
+{
+ QSize raster = rect.size() / 2;
+
+ const QRectF pixelRect = pixelHint( area );
+ if ( !pixelRect.isEmpty() )
+ {
+ const QSize res( qCeil( rect.width() / pixelRect.width() ),
+ qCeil( rect.height() / pixelRect.height() ) );
+ raster = raster.boundedTo( res );
+ }
+
+ return raster;
+}
+
+/*!
+ Calculate contour lines
+
+ \param rect Rectangle, where to calculate the contour lines
+ \param raster Raster, used by the CONREC algorithm
+
+ \sa contourLevels(), setConrecFlag(),
+ QwtRasterData::contourLines()
+*/
+QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
+ const QRectF &rect, const QSize &raster ) const
+{
+ if ( d_data->data == NULL )
+ return QwtRasterData::ContourLines();
+
+ return d_data->data->contourLines( rect, raster,
+ d_data->contourLevels, d_data->conrecFlags );
+}
+
+/*!
+ Paint the contour lines
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param contourLines Contour lines
+
+ \sa renderContourLines(), defaultContourPen(), contourPen()
+*/
+void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QwtRasterData::ContourLines &contourLines ) const
+{
+ if ( d_data->data == NULL )
+ return;
+
+ const int numLevels = d_data->contourLevels.size();
+ for ( int l = 0; l < numLevels; l++ )
+ {
+ const double level = d_data->contourLevels[l];
+
+ QPen pen = defaultContourPen();
+ if ( pen.style() == Qt::NoPen )
+ pen = contourPen( level );
+
+ if ( pen.style() == Qt::NoPen )
+ continue;
+
+ painter->setPen( pen );
+
+ const QPolygonF &lines = contourLines[level];
+ for ( int i = 0; i < lines.size(); i += 2 )
+ {
+ const QPointF p1( xMap.transform( lines[i].x() ),
+ yMap.transform( lines[i].y() ) );
+ const QPointF p2( xMap.transform( lines[i+1].x() ),
+ yMap.transform( lines[i+1].y() ) );
+
+ QwtPainter::drawLine( painter, p1, p2 );
+ }
+ }
+}
+
+/*!
+ \brief Draw the spectrogram
+
+ \param painter Painter
+ \param xMap Maps x-values into pixel coordinates.
+ \param yMap Maps y-values into pixel coordinates.
+ \param canvasRect Contents rect of the canvas in painter coordinates
+
+ \sa setDisplayMode(), renderImage(),
+ QwtPlotRasterItem::draw(), drawContourLines()
+*/
+void QwtPlotSpectrogram::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ if ( d_data->displayMode & ImageMode )
+ QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
+
+ if ( d_data->displayMode & ContourMode )
+ {
+ // Add some pixels at the borders
+ const int margin = 2;
+ QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
+ canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
+
+ QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
+
+ const QRectF br = boundingRect();
+ if ( br.isValid() )
+ {
+ area &= br;
+ if ( area.isEmpty() )
+ return;
+
+ rasterRect = QwtScaleMap::transform( xMap, yMap, area );
+ }
+
+ QSize raster = contourRasterSize( area, rasterRect.toRect() );
+ raster = raster.boundedTo( rasterRect.toRect().size() );
+ if ( raster.isValid() )
+ {
+ const QwtRasterData::ContourLines lines =
+ renderContourLines( area, raster );
+
+ drawContourLines( painter, xMap, yMap, lines );
+ }
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_spectrogram.h b/src/libpcp_qwt/src/qwt_plot_spectrogram.h
new file mode 100644
index 0000000..423507c
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_spectrogram.h
@@ -0,0 +1,115 @@
+/* -*- 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_PLOT_SPECTROGRAM_H
+#define QWT_PLOT_SPECTROGRAM_H
+
+#include "qwt_global.h"
+#include "qwt_raster_data.h"
+#include "qwt_plot_rasteritem.h"
+#include <qlist.h>
+
+class QwtColorMap;
+
+/*!
+ \brief A plot item, which displays a spectrogram
+
+ A spectrogram displays threedimenional data, where the 3rd dimension
+ ( the intensity ) is displayed using colors. The colors are calculated
+ from the values using a color map.
+
+ In ContourMode contour lines are painted for the contour levels.
+
+ \image html spectrogram3.png
+
+ \sa QwtRasterData, QwtColorMap
+*/
+
+class QWT_EXPORT QwtPlotSpectrogram: public QwtPlotRasterItem
+{
+public:
+ /*!
+ The display mode controls how the raster data will be represented.
+ \sa setDisplayMode(), testDisplayMode()
+ */
+
+ enum DisplayMode
+ {
+ //! The values are mapped to colors using a color map.
+ ImageMode = 0x01,
+
+ //! The data is displayed using contour lines
+ ContourMode = 0x02
+ };
+
+ //! Display modes
+ typedef QFlags<DisplayMode> DisplayModes;
+
+ explicit QwtPlotSpectrogram( const QString &title = QString::null );
+ virtual ~QwtPlotSpectrogram();
+
+ void setRenderThreadCount( uint numThreads );
+ uint renderThreadCount() const;
+
+ void setDisplayMode( DisplayMode, bool on = true );
+ bool testDisplayMode( DisplayMode ) const;
+
+ void setData( QwtRasterData *data );
+ const QwtRasterData *data() const;
+ QwtRasterData *data();
+
+ void setColorMap( QwtColorMap * );
+ const QwtColorMap *colorMap() const;
+
+ virtual QwtInterval interval(Qt::Axis) const;
+ virtual QRectF pixelHint( const QRectF & ) const;
+
+ void setDefaultContourPen( const QPen & );
+ QPen defaultContourPen() const;
+
+ virtual QPen contourPen( double level ) const;
+
+ void setConrecFlag( QwtRasterData::ConrecFlag, bool on );
+ bool testConrecFlag( QwtRasterData::ConrecFlag ) const;
+
+ void setContourLevels( const QList<double> & );
+ QList<double> contourLevels() const;
+
+ virtual int rtti() const;
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &rect ) const;
+
+protected:
+ virtual QImage renderImage(
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &area, const QSize &imageSize ) const;
+
+ virtual QSize contourRasterSize(
+ const QRectF &, const QRect & ) const;
+
+ virtual QwtRasterData::ContourLines renderContourLines(
+ const QRectF &rect, const QSize &raster ) const;
+
+ virtual void drawContourLines( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QwtRasterData::ContourLines& lines ) const;
+
+ void renderTile( const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRect &imageRect, QImage *image ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotSpectrogram::DisplayModes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_svgitem.cpp b/src/libpcp_qwt/src/qwt_plot_svgitem.cpp
new file mode 100644
index 0000000..c84395d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_svgitem.cpp
@@ -0,0 +1,214 @@
+/* -*- 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_plot_svgitem.h"
+#include "qwt_scale_map.h"
+#include "qwt_legend.h"
+#include "qwt_legend_item.h"
+#include "qwt_painter.h"
+#include <qpainter.h>
+#include <qsvgrenderer.h>
+
+class QwtPlotSvgItem::PrivateData
+{
+public:
+ PrivateData()
+ {
+ }
+
+ QRectF boundingRect;
+ QSvgRenderer renderer;
+};
+
+/*!
+ \brief Constructor
+
+ Sets the following item attributes:
+ - QwtPlotItem::AutoScale: true
+ - QwtPlotItem::Legend: false
+
+ \param title Title
+*/
+QwtPlotSvgItem::QwtPlotSvgItem( const QString& title ):
+ QwtPlotItem( QwtText( title ) )
+{
+ init();
+}
+
+/*!
+ \brief Constructor
+
+ Sets the following item attributes:
+ - QwtPlotItem::AutoScale: true
+ - QwtPlotItem::Legend: false
+
+ \param title Title
+*/
+QwtPlotSvgItem::QwtPlotSvgItem( const QwtText& title ):
+ QwtPlotItem( title )
+{
+ init();
+}
+
+//! Destructor
+QwtPlotSvgItem::~QwtPlotSvgItem()
+{
+ delete d_data;
+}
+
+void QwtPlotSvgItem::init()
+{
+ d_data = new PrivateData();
+
+ setItemAttribute( QwtPlotItem::AutoScale, true );
+ setItemAttribute( QwtPlotItem::Legend, false );
+
+ setZ( 8.0 );
+}
+
+//! \return QwtPlotItem::Rtti_PlotSVG
+int QwtPlotSvgItem::rtti() const
+{
+ return QwtPlotItem::Rtti_PlotSVG;
+}
+
+/*!
+ Load a SVG file
+
+ \param rect Bounding rectangle
+ \param fileName SVG file name
+
+ \return true, if the SVG file could be loaded
+*/
+bool QwtPlotSvgItem::loadFile( const QRectF &rect,
+ const QString &fileName )
+{
+ d_data->boundingRect = rect;
+ const bool ok = d_data->renderer.load( fileName );
+ itemChanged();
+ return ok;
+}
+
+/*!
+ Load SVG data
+
+ \param rect Bounding rectangle
+ \param data in SVG format
+
+ \return true, if the SVG data could be loaded
+*/
+bool QwtPlotSvgItem::loadData( const QRectF &rect,
+ const QByteArray &data )
+{
+ d_data->boundingRect = rect;
+ const bool ok = d_data->renderer.load( data );
+ itemChanged();
+ return ok;
+}
+
+//! Bounding rect of the item
+QRectF QwtPlotSvgItem::boundingRect() const
+{
+ return d_data->boundingRect;
+}
+
+//! \return Renderer used to render the SVG data
+const QSvgRenderer &QwtPlotSvgItem::renderer() const
+{
+ return d_data->renderer;
+}
+
+//! \return Renderer used to render the SVG data
+QSvgRenderer &QwtPlotSvgItem::renderer()
+{
+ return d_data->renderer;
+}
+
+/*!
+ Draw the SVG item
+
+ \param painter Painter
+ \param xMap X-Scale Map
+ \param yMap Y-Scale Map
+ \param canvasRect Contents rect of the plot canvas
+*/
+void QwtPlotSvgItem::draw( QPainter *painter,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &canvasRect ) const
+{
+ const QRectF cRect = QwtScaleMap::invTransform(
+ xMap, yMap, canvasRect.toRect() );
+ const QRectF bRect = boundingRect();
+ if ( bRect.isValid() && cRect.isValid() )
+ {
+ QRectF rect = bRect;
+ if ( bRect.contains( cRect ) )
+ rect = cRect;
+
+ const QRectF r = QwtScaleMap::transform( xMap, yMap, rect );
+ render( painter, viewBox( rect ), r );
+ }
+}
+
+/*!
+ Render the SVG data
+
+ \param painter Painter
+ \param viewBox View Box, see QSvgRenderer::viewBox
+ \param rect Traget rectangle on the paint device
+*/
+void QwtPlotSvgItem::render( QPainter *painter,
+ const QRectF &viewBox, const QRectF &rect ) const
+{
+ if ( !viewBox.isValid() )
+ return;
+
+ QRectF r = rect;
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ r.setLeft ( qRound( r.left() ) );
+ r.setRight ( qRound( r.right() ) );
+ r.setTop ( qRound( r.top() ) );
+ r.setBottom ( qRound( r.bottom() ) );
+ }
+
+ d_data->renderer.setViewBox( viewBox );
+ d_data->renderer.render( painter, r );
+}
+
+/*!
+ Calculate the viewBox from an rect and boundingRect().
+
+ \param rect Rectangle in scale coordinates
+ \return viewBox View Box, see QSvgRenderer::viewBox
+*/
+QRectF QwtPlotSvgItem::viewBox( const QRectF &rect ) const
+{
+ const QSize sz = d_data->renderer.defaultSize();
+ const QRectF br = boundingRect();
+
+ if ( !rect.isValid() || !br.isValid() || sz.isNull() )
+ return QRectF();
+
+ QwtScaleMap xMap;
+ xMap.setScaleInterval( br.left(), br.right() );
+ xMap.setPaintInterval( 0, sz.width() );
+
+ QwtScaleMap yMap;
+ yMap.setScaleInterval( br.top(), br.bottom() );
+ yMap.setPaintInterval( sz.height(), 0 );
+
+ const double x1 = xMap.transform( rect.left() );
+ const double x2 = xMap.transform( rect.right() );
+ const double y1 = yMap.transform( rect.bottom() );
+ const double y2 = yMap.transform( rect.top() );
+
+ return QRectF( x1, y1, x2 - x1, y2 - y1 );
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_svgitem.h b/src/libpcp_qwt/src/qwt_plot_svgitem.h
new file mode 100644
index 0000000..1d98dee
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_svgitem.h
@@ -0,0 +1,61 @@
+/* -*- 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_PLOT_SVGITEM_H
+#define QWT_PLOT_SVGITEM_H
+
+#include "qwt_global.h"
+#include "qwt_plot_item.h"
+#include <qstring.h>
+
+class QSvgRenderer;
+class QByteArray;
+
+/*!
+ \brief A plot item, which displays
+ data in Scalable Vector Graphics (SVG) format.
+
+ SVG images are often used to display maps
+*/
+
+class QWT_EXPORT QwtPlotSvgItem: public QwtPlotItem
+{
+public:
+ explicit QwtPlotSvgItem( const QString& title = QString::null );
+ explicit QwtPlotSvgItem( const QwtText& title );
+ virtual ~QwtPlotSvgItem();
+
+ bool loadFile( const QRectF&, const QString &fileName );
+ bool loadData( const QRectF&, const QByteArray & );
+
+ virtual QRectF boundingRect() const;
+
+ virtual void draw( QPainter *p,
+ const QwtScaleMap &xMap, const QwtScaleMap &yMap,
+ const QRectF &rect ) const;
+
+ virtual int rtti() const;
+
+protected:
+ const QSvgRenderer &renderer() const;
+ QSvgRenderer &renderer();
+
+ void render( QPainter *painter,
+ const QRectF &viewBox, const QRectF &rect ) const;
+
+ QRectF viewBox( const QRectF &area ) const;
+
+private:
+ void init();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_plot_xml.cpp b/src/libpcp_qwt/src/qwt_plot_xml.cpp
new file mode 100644
index 0000000..0e72a29
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_xml.cpp
@@ -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
+ *****************************************************************************/
+
+#include "qwt_plot.h"
+
+/*!
+ This method is intended for manipulating the plot widget
+ from a specific editor in the Qwt designer plugin.
+
+ \warning The plot editor has never been implemented.
+*/
+void QwtPlot::applyProperties( const QString & /* xmlDocument */ )
+{
+#if 0
+ // Temporary dummy code, for designer tests
+ setTitle( xmlDocument );
+ replot();
+#endif
+}
+
+/*!
+ This method is intended for manipulating the plot widget
+ from a specific editor in the Qwt designer plugin.
+
+ \warning The plot editor has never been implemented.
+*/
+QString QwtPlot::grabProperties() const
+{
+#if 0
+ // Temporary dummy code, for designer tests
+ return title().text();
+#else
+ return QString::null;
+#endif
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_zoomer.cpp b/src/libpcp_qwt/src/qwt_plot_zoomer.cpp
new file mode 100644
index 0000000..2add7d4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_zoomer.cpp
@@ -0,0 +1,607 @@
+/* -*- 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_plot_zoomer.h"
+#include "qwt_plot.h"
+#include "qwt_plot_canvas.h"
+#include "qwt_scale_div.h"
+#include "qwt_picker_machine.h"
+#include <qalgorithms.h>
+
+class QwtPlotZoomer::PrivateData
+{
+public:
+ uint zoomRectIndex;
+ QStack<QRectF> zoomStack;
+
+ int maxStackDepth;
+};
+
+/*!
+ \brief Create a zoomer for a plot canvas.
+
+ The zoomer is set to those x- and y-axis of the parent plot of the
+ canvas that are enabled. If both or no x-axis are enabled, the picker
+ is set to QwtPlot::xBottom. If both or no y-axis are
+ enabled, it is set to QwtPlot::yLeft.
+
+ The zoomer is initialized with a QwtPickerDragRectMachine,
+ the tracker mode is set to QwtPicker::ActiveOnly and the rubberband
+ is set to QwtPicker::RectRubberBand
+
+ \param canvas Plot canvas to observe, also the parent object
+ \param doReplot Call replot for the attached plot before initializing
+ the zoomer with its scales. This might be necessary,
+ when the plot is in a state with pending scale changes.
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase()
+*/
+QwtPlotZoomer::QwtPlotZoomer( QwtPlotCanvas *canvas, bool doReplot ):
+ QwtPlotPicker( canvas )
+{
+ if ( canvas )
+ init( doReplot );
+}
+
+/*!
+ \brief Create a zoomer for a plot canvas.
+
+ The zoomer is initialized with a QwtPickerDragRectMachine,
+ the tracker mode is set to QwtPicker::ActiveOnly and the rubberband
+ is set to QwtPicker;;RectRubberBand
+
+ \param xAxis X axis of the zoomer
+ \param yAxis Y axis of the zoomer
+ \param canvas Plot canvas to observe, also the parent object
+ \param doReplot Call replot for the attached plot before initializing
+ the zoomer with its scales. This might be necessary,
+ when the plot is in a state with pending scale changes.
+
+ \sa QwtPlot::autoReplot(), QwtPlot::replot(), setZoomBase()
+*/
+
+QwtPlotZoomer::QwtPlotZoomer( int xAxis, int yAxis,
+ QwtPlotCanvas *canvas, bool doReplot ):
+ QwtPlotPicker( xAxis, yAxis, canvas )
+{
+ if ( canvas )
+ init( doReplot );
+}
+
+//! Init the zoomer, used by the constructors
+void QwtPlotZoomer::init( bool doReplot )
+{
+ d_data = new PrivateData;
+
+ d_data->maxStackDepth = -1;
+
+ setTrackerMode( ActiveOnly );
+ setRubberBand( RectRubberBand );
+ setStateMachine( new QwtPickerDragRectMachine() );
+
+ if ( doReplot && plot() )
+ plot()->replot();
+
+ setZoomBase( scaleRect() );
+}
+
+QwtPlotZoomer::~QwtPlotZoomer()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Limit the number of recursive zoom operations to depth.
+
+ A value of -1 set the depth to unlimited, 0 disables zooming.
+ If the current zoom rectangle is below depth, the plot is unzoomed.
+
+ \param depth Maximum for the stack depth
+ \sa maxStackDepth()
+ \note depth doesn't include the zoom base, so zoomStack().count() might be
+ maxStackDepth() + 1.
+*/
+void QwtPlotZoomer::setMaxStackDepth( int depth )
+{
+ d_data->maxStackDepth = depth;
+
+ if ( depth >= 0 )
+ {
+ // unzoom if the current depth is below d_data->maxStackDepth
+
+ const int zoomOut =
+ int( d_data->zoomStack.count() ) - 1 - depth; // -1 for the zoom base
+
+ if ( zoomOut > 0 )
+ {
+ zoom( -zoomOut );
+ for ( int i = int( d_data->zoomStack.count() ) - 1;
+ i > int( d_data->zoomRectIndex ); i-- )
+ {
+ ( void )d_data->zoomStack.pop(); // remove trailing rects
+ }
+ }
+ }
+}
+
+/*!
+ \return Maximal depth of the zoom stack.
+ \sa setMaxStackDepth()
+*/
+int QwtPlotZoomer::maxStackDepth() const
+{
+ return d_data->maxStackDepth;
+}
+
+/*!
+ Return the zoom stack. zoomStack()[0] is the zoom base,
+ zoomStack()[1] the first zoomed rectangle.
+
+ \sa setZoomStack(), zoomRectIndex()
+*/
+const QStack<QRectF> &QwtPlotZoomer::zoomStack() const
+{
+ return d_data->zoomStack;
+}
+
+/*!
+ \return Initial rectangle of the zoomer
+ \sa setZoomBase(), zoomRect()
+*/
+QRectF QwtPlotZoomer::zoomBase() const
+{
+ return d_data->zoomStack[0];
+}
+
+/*!
+ Reinitialized the zoom stack with scaleRect() as base.
+
+ \param doReplot Call replot for the attached plot before initializing
+ the zoomer with its scales. This might be necessary,
+ when the plot is in a state with pending scale changes.
+
+ \sa zoomBase(), scaleRect() QwtPlot::autoReplot(), QwtPlot::replot().
+*/
+void QwtPlotZoomer::setZoomBase( bool doReplot )
+{
+ QwtPlot *plt = plot();
+ if ( plt == NULL )
+ return;
+
+ if ( doReplot )
+ plt->replot();
+
+ d_data->zoomStack.clear();
+ d_data->zoomStack.push( scaleRect() );
+ d_data->zoomRectIndex = 0;
+
+ rescale();
+}
+
+/*!
+ \brief Set the initial size of the zoomer.
+
+ base is united with the current scaleRect() and the zoom stack is
+ reinitalized with it as zoom base. plot is zoomed to scaleRect().
+
+ \param base Zoom base
+
+ \sa zoomBase(), scaleRect()
+*/
+void QwtPlotZoomer::setZoomBase( const QRectF &base )
+{
+ const QwtPlot *plt = plot();
+ if ( !plt )
+ return;
+
+ const QRectF sRect = scaleRect();
+ const QRectF bRect = base | sRect;
+
+ d_data->zoomStack.clear();
+ d_data->zoomStack.push( bRect );
+ d_data->zoomRectIndex = 0;
+
+ if ( base != sRect )
+ {
+ d_data->zoomStack.push( sRect );
+ d_data->zoomRectIndex++;
+ }
+
+ rescale();
+}
+
+/*!
+ Rectangle at the current position on the zoom stack.
+
+ \sa zoomRectIndex(), scaleRect().
+*/
+QRectF QwtPlotZoomer::zoomRect() const
+{
+ return d_data->zoomStack[d_data->zoomRectIndex];
+}
+
+/*!
+ \return Index of current position of zoom stack.
+*/
+uint QwtPlotZoomer::zoomRectIndex() const
+{
+ return d_data->zoomRectIndex;
+}
+
+/*!
+ \brief Zoom in
+
+ Clears all rectangles above the current position of the
+ zoom stack and pushs the normalized rect on it.
+
+ \note If the maximal stack depth is reached, zoom is ignored.
+ \note The zoomed signal is emitted.
+*/
+
+void QwtPlotZoomer::zoom( const QRectF &rect )
+{
+ if ( d_data->maxStackDepth >= 0 &&
+ int( d_data->zoomRectIndex ) >= d_data->maxStackDepth )
+ {
+ return;
+ }
+
+ const QRectF zoomRect = rect.normalized();
+ if ( zoomRect != d_data->zoomStack[d_data->zoomRectIndex] )
+ {
+ for ( uint i = int( d_data->zoomStack.count() ) - 1;
+ i > d_data->zoomRectIndex; i-- )
+ {
+ ( void )d_data->zoomStack.pop();
+ }
+
+ d_data->zoomStack.push( zoomRect );
+ d_data->zoomRectIndex++;
+
+ rescale();
+
+ Q_EMIT zoomed( zoomRect );
+ }
+}
+
+/*!
+ \brief Zoom in or out
+
+ Activate a rectangle on the zoom stack with an offset relative
+ to the current position. Negative values of offest will zoom out,
+ positive zoom in. A value of 0 zooms out to the zoom base.
+
+ \param offset Offset relative to the current position of the zoom stack.
+ \note The zoomed signal is emitted.
+ \sa zoomRectIndex()
+*/
+void QwtPlotZoomer::zoom( int offset )
+{
+ if ( offset == 0 )
+ d_data->zoomRectIndex = 0;
+ else
+ {
+ int newIndex = d_data->zoomRectIndex + offset;
+ newIndex = qMax( 0, newIndex );
+ newIndex = qMin( int( d_data->zoomStack.count() ) - 1, newIndex );
+
+ d_data->zoomRectIndex = uint( newIndex );
+ }
+
+ rescale();
+
+ Q_EMIT zoomed( zoomRect() );
+}
+
+/*!
+ \brief Assign a zoom stack
+
+ In combination with other types of navigation it might be useful to
+ modify to manipulate the complete zoom stack.
+
+ \param zoomStack New zoom stack
+ \param zoomRectIndex Index of the current position of zoom stack.
+ In case of -1 the current position is at the top
+ of the stack.
+
+ \note The zoomed signal might be emitted.
+ \sa zoomStack(), zoomRectIndex()
+*/
+void QwtPlotZoomer::setZoomStack(
+ const QStack<QRectF> &zoomStack, int zoomRectIndex )
+{
+ if ( zoomStack.isEmpty() )
+ return;
+
+ if ( d_data->maxStackDepth >= 0 &&
+ int( zoomStack.count() ) > d_data->maxStackDepth )
+ {
+ return;
+ }
+
+ if ( zoomRectIndex < 0 || zoomRectIndex > int( zoomStack.count() ) )
+ zoomRectIndex = zoomStack.count() - 1;
+
+ const bool doRescale = zoomStack[zoomRectIndex] != zoomRect();
+
+ d_data->zoomStack = zoomStack;
+ d_data->zoomRectIndex = uint( zoomRectIndex );
+
+ if ( doRescale )
+ {
+ rescale();
+ Q_EMIT zoomed( zoomRect() );
+ }
+}
+
+/*!
+ Adjust the observed plot to zoomRect()
+
+ \note Initiates QwtPlot::replot
+*/
+
+void QwtPlotZoomer::rescale()
+{
+ QwtPlot *plt = plot();
+ if ( !plt )
+ return;
+
+ const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
+ if ( rect != scaleRect() )
+ {
+ const bool doReplot = plt->autoReplot();
+ plt->setAutoReplot( false );
+
+ double x1 = rect.left();
+ double x2 = rect.right();
+ if ( plt->axisScaleDiv( xAxis() )->lowerBound() >
+ plt->axisScaleDiv( xAxis() )->upperBound() )
+ {
+ qSwap( x1, x2 );
+ }
+
+ plt->setAxisScale( xAxis(), x1, x2 );
+
+ double y1 = rect.top();
+ double y2 = rect.bottom();
+ if ( plt->axisScaleDiv( yAxis() )->lowerBound() >
+ plt->axisScaleDiv( yAxis() )->upperBound() )
+ {
+ qSwap( y1, y2 );
+ }
+ plt->setAxisScale( yAxis(), y1, y2 );
+
+ plt->setAutoReplot( doReplot );
+
+ plt->replot();
+ }
+}
+
+/*!
+ Reinitialize the axes, and set the zoom base to their scales.
+
+ \param xAxis X axis
+ \param yAxis Y axis
+*/
+
+void QwtPlotZoomer::setAxis( int xAxis, int yAxis )
+{
+ if ( xAxis != QwtPlotPicker::xAxis() || yAxis != QwtPlotPicker::yAxis() )
+ {
+ QwtPlotPicker::setAxis( xAxis, yAxis );
+ setZoomBase( scaleRect() );
+ }
+}
+
+/*!
+ Qt::MidButton zooms out one position on the zoom stack,
+ Qt::RightButton to the zoom base.
+
+ Changes the current position on the stack, but doesn't pop
+ any rectangle.
+
+ \note The mouse events can be changed, using
+ QwtEventPattern::setMousePattern: 2, 1
+*/
+void QwtPlotZoomer::widgetMouseReleaseEvent( QMouseEvent *me )
+{
+ if ( mouseMatch( MouseSelect2, me ) )
+ zoom( 0 );
+ else if ( mouseMatch( MouseSelect3, me ) )
+ zoom( -1 );
+ else if ( mouseMatch( MouseSelect6, me ) )
+ zoom( +1 );
+ else
+ QwtPlotPicker::widgetMouseReleaseEvent( me );
+}
+
+/*!
+ Qt::Key_Plus zooms in, Qt::Key_Minus zooms out one position on the
+ zoom stack, Qt::Key_Escape zooms out to the zoom base.
+
+ Changes the current position on the stack, but doesn't pop
+ any rectangle.
+
+ \note The keys codes can be changed, using
+ QwtEventPattern::setKeyPattern: 3, 4, 5
+*/
+
+void QwtPlotZoomer::widgetKeyPressEvent( QKeyEvent *ke )
+{
+ if ( !isActive() )
+ {
+ if ( keyMatch( KeyUndo, ke ) )
+ zoom( -1 );
+ else if ( keyMatch( KeyRedo, ke ) )
+ zoom( +1 );
+ else if ( keyMatch( KeyHome, ke ) )
+ zoom( 0 );
+ }
+
+ QwtPlotPicker::widgetKeyPressEvent( ke );
+}
+
+/*!
+ Move the current zoom rectangle.
+
+ \param dx X offset
+ \param dy Y offset
+
+ \note The changed rectangle is limited by the zoom base
+*/
+void QwtPlotZoomer::moveBy( double dx, double dy )
+{
+ const QRectF &rect = d_data->zoomStack[d_data->zoomRectIndex];
+ moveTo( QPointF( rect.left() + dx, rect.top() + dy ) );
+}
+
+/*!
+ Move the the current zoom rectangle.
+
+ \param pos New position
+
+ \sa QRectF::moveTo()
+ \note The changed rectangle is limited by the zoom base
+*/
+void QwtPlotZoomer::moveTo( const QPointF &pos )
+{
+ double x = pos.x();
+ double y = pos.y();
+
+ if ( x < zoomBase().left() )
+ x = zoomBase().left();
+ if ( x > zoomBase().right() - zoomRect().width() )
+ x = zoomBase().right() - zoomRect().width();
+
+ if ( y < zoomBase().top() )
+ y = zoomBase().top();
+ if ( y > zoomBase().bottom() - zoomRect().height() )
+ y = zoomBase().bottom() - zoomRect().height();
+
+ if ( x != zoomRect().left() || y != zoomRect().top() )
+ {
+ d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
+ rescale();
+ }
+}
+
+/*!
+ \brief Check and correct a selected rectangle
+
+ Reject rectangles with a hight or width < 2, otherwise
+ expand the selected rectangle to a minimum size of 11x11
+ and accept it.
+
+ \return true If rect is accepted, or has been changed
+ to a accepted rectangle.
+*/
+
+bool QwtPlotZoomer::accept( QPolygon &pa ) const
+{
+ if ( pa.count() < 2 )
+ return false;
+
+ QRect rect = QRect( pa[0], pa[int( pa.count() ) - 1] );
+ rect = rect.normalized();
+
+ const int minSize = 2;
+ if ( rect.width() < minSize && rect.height() < minSize )
+ return false;
+
+ const int minZoomSize = 11;
+
+ const QPoint center = rect.center();
+ rect.setSize( rect.size().expandedTo( QSize( minZoomSize, minZoomSize ) ) );
+ rect.moveCenter( center );
+
+ pa.resize( 2 );
+ pa[0] = rect.topLeft();
+ pa[1] = rect.bottomRight();
+
+ return true;
+}
+
+/*!
+ \brief Limit zooming by a minimum rectangle
+
+ \return zoomBase().width() / 10e4, zoomBase().height() / 10e4
+*/
+QSizeF QwtPlotZoomer::minZoomSize() const
+{
+ return QSizeF( d_data->zoomStack[0].width() / 10e4,
+ d_data->zoomStack[0].height() / 10e4 );
+}
+
+/*!
+ Rejects selections, when the stack depth is too deep, or
+ the zoomed rectangle is minZoomSize().
+
+ \sa minZoomSize(), maxStackDepth()
+*/
+void QwtPlotZoomer::begin()
+{
+ if ( d_data->maxStackDepth >= 0 )
+ {
+ if ( d_data->zoomRectIndex >= uint( d_data->maxStackDepth ) )
+ return;
+ }
+
+ const QSizeF minSize = minZoomSize();
+ if ( minSize.isValid() )
+ {
+ const QSizeF sz =
+ d_data->zoomStack[d_data->zoomRectIndex].size() * 0.9999;
+
+ if ( minSize.width() >= sz.width() &&
+ minSize.height() >= sz.height() )
+ {
+ return;
+ }
+ }
+
+ QwtPlotPicker::begin();
+}
+
+/*!
+ Expand the selected rectangle to minZoomSize() and zoom in
+ if accepted.
+
+ \sa accept(), minZoomSize()
+*/
+bool QwtPlotZoomer::end( bool ok )
+{
+ ok = QwtPlotPicker::end( ok );
+ if ( !ok )
+ return false;
+
+ QwtPlot *plot = QwtPlotZoomer::plot();
+ if ( !plot )
+ return false;
+
+ const QPolygon &pa = selection();
+ if ( pa.count() < 2 )
+ return false;
+
+ QRect rect = QRect( pa[0], pa[int( pa.count() - 1 )] );
+ rect = rect.normalized();
+
+ QRectF zoomRect = invTransform( rect ).normalized();
+
+ const QSizeF minSize = minZoomSize();
+ if ( minSize.isValid() )
+ {
+ const QPointF center = zoomRect.center();
+ zoomRect.setSize( zoomRect.size().expandedTo( minZoomSize() ) );
+ zoomRect.moveCenter( center );
+ }
+
+ zoom( zoomRect );
+
+ return true;
+}
diff --git a/src/libpcp_qwt/src/qwt_plot_zoomer.h b/src/libpcp_qwt/src/qwt_plot_zoomer.h
new file mode 100644
index 0000000..84e23c7
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_plot_zoomer.h
@@ -0,0 +1,104 @@
+/* -*- 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_PLOT_ZOOMER_H
+#define QWT_PLOT_ZOOMER_H
+
+#include "qwt_global.h"
+#include "qwt_plot_picker.h"
+#include <qstack.h>
+
+/*!
+ \brief QwtPlotZoomer provides stacked zooming for a plot widget
+
+ QwtPlotZoomer offers rubberband selections on the plot canvas,
+ translating the selected rectangles into plot coordinates and
+ adjusting the axes to them. Zooming can repeated as often as
+ possible, limited only by maxStackDepth() or minZoomSize().
+ Each rectangle is pushed on a stack.
+
+ Zoom rectangles can be selected depending on selectionFlags() using the
+ mouse or keyboard (QwtEventPattern, QwtPickerMachine).
+ QwtEventPattern::MouseSelect3,QwtEventPattern::KeyUndo,
+ or QwtEventPattern::MouseSelect6,QwtEventPattern::KeyRedo
+ walk up and down the zoom stack.
+ QwtEventPattern::MouseSelect2 or QwtEventPattern::KeyHome unzoom to
+ the initial size.
+
+ QwtPlotZoomer is tailored for plots with one x and y axis, but it is
+ allowed to attach a second QwtPlotZoomer for the other axes.
+
+ \note The realtime example includes an derived zoomer class that adds
+ scrollbars to the plot canvas.
+*/
+
+class QWT_EXPORT QwtPlotZoomer: public QwtPlotPicker
+{
+ Q_OBJECT
+public:
+ explicit QwtPlotZoomer( QwtPlotCanvas *, bool doReplot = true );
+ explicit QwtPlotZoomer( int xAxis, int yAxis,
+ QwtPlotCanvas *, bool doReplot = true );
+
+ virtual ~QwtPlotZoomer();
+
+ virtual void setZoomBase( bool doReplot = true );
+ virtual void setZoomBase( const QRectF & );
+
+ QRectF zoomBase() const;
+ QRectF zoomRect() const;
+
+ virtual void setAxis( int xAxis, int yAxis );
+
+ void setMaxStackDepth( int );
+ int maxStackDepth() const;
+
+ const QStack<QRectF> &zoomStack() const;
+ void setZoomStack( const QStack<QRectF> &,
+ int zoomRectIndex = -1 );
+
+ uint zoomRectIndex() const;
+
+public Q_SLOTS:
+ void moveBy( double x, double y );
+ virtual void moveTo( const QPointF & );
+
+ virtual void zoom( const QRectF & );
+ virtual void zoom( int up );
+
+Q_SIGNALS:
+ /*!
+ A signal emitting the zoomRect(), when the plot has been
+ zoomed in or out.
+
+ \param rect Current zoom rectangle.
+ */
+
+ void zoomed( const QRectF &rect );
+
+protected:
+ virtual void rescale();
+
+ virtual QSizeF minZoomSize() const;
+
+ virtual void widgetMouseReleaseEvent( QMouseEvent * );
+ virtual void widgetKeyPressEvent( QKeyEvent * );
+
+ virtual void begin();
+ virtual bool end( bool ok = true );
+ virtual bool accept( QPolygon & ) const;
+
+private:
+ void init( bool doReplot );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_point_3d.cpp b/src/libpcp_qwt/src/qwt_point_3d.cpp
new file mode 100644
index 0000000..27e4c1e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_point_3d.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
+ *****************************************************************************/
+
+#include "qwt_point_3d.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<( QDebug debug, const QwtPoint3D &point )
+{
+ debug.nospace() << "QwtPoint3D(" << point.x()
+ << "," << point.y() << "," << point.z() << ")";
+ return debug.space();
+}
+
+#endif
+
diff --git a/src/libpcp_qwt/src/qwt_point_3d.h b/src/libpcp_qwt/src/qwt_point_3d.h
new file mode 100644
index 0000000..ac18938
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_point_3d.h
@@ -0,0 +1,189 @@
+/* -*- 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
+ *****************************************************************************/
+
+/*! \file */
+#ifndef QWT_POINT_3D_H
+#define QWT_POINT_3D_H 1
+
+#include "qwt_global.h"
+#include <qpoint.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <qdebug.h>
+#endif
+
+/*!
+ \brief QwtPoint3D class defines a 3D point in double coordinates
+*/
+
+class QWT_EXPORT QwtPoint3D
+{
+public:
+ QwtPoint3D();
+ QwtPoint3D( double x, double y, double z );
+ QwtPoint3D( const QwtPoint3D & );
+ QwtPoint3D( const QPointF & );
+
+ bool isNull() const;
+
+ double x() const;
+ double y() const;
+ double z() const;
+
+ double &rx();
+ double &ry();
+ double &rz();
+
+ void setX( double x );
+ void setY( double y );
+ void setZ( double y );
+
+ QPointF toPoint() const;
+
+ bool operator==( const QwtPoint3D & ) const;
+ bool operator!=( const QwtPoint3D & ) const;
+
+private:
+ double d_x;
+ double d_y;
+ double d_z;
+};
+
+Q_DECLARE_TYPEINFO(QwtPoint3D, Q_MOVABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+QWT_EXPORT QDebug operator<<( QDebug, const QwtPoint3D & );
+#endif
+
+/*!
+ Constructs a null point.
+ \sa isNull()
+*/
+inline QwtPoint3D::QwtPoint3D():
+ d_x( 0.0 ),
+ d_y( 0.0 ),
+ d_z( 0.0 )
+{
+}
+
+//! Constructs a point with coordinates specified by x, y and z.
+inline QwtPoint3D::QwtPoint3D( double x, double y, double z = 0.0 ):
+ d_x( x ),
+ d_y( y ),
+ d_z( z )
+{
+}
+
+/*!
+ Copy constructor.
+ Constructs a point using the values of the point specified.
+*/
+inline QwtPoint3D::QwtPoint3D( const QwtPoint3D &other ):
+ d_x( other.d_x ),
+ d_y( other.d_y ),
+ d_z( other.d_z )
+{
+}
+
+/*!
+ Constructs a point with x and y coordinates from a 2D point,
+ and a z coordinate of 0.
+*/
+inline QwtPoint3D::QwtPoint3D( const QPointF &other ):
+ d_x( other.x() ),
+ d_y( other.y() ),
+ d_z( 0.0 )
+{
+}
+
+/*!
+ Returns true if the point is null; otherwise returns false.
+
+ A point is considered to be null if x, y and z-coordinates
+ are equal to zero.
+*/
+inline bool QwtPoint3D::isNull() const
+{
+ return d_x == 0.0 && d_y == 0.0 && d_z == 0.0;
+}
+
+//! Returns the x-coordinate of the point.
+inline double QwtPoint3D::x() const
+{
+ return d_x;
+}
+
+//! Returns the y-coordinate of the point.
+inline double QwtPoint3D::y() const
+{
+ return d_y;
+}
+
+//! Returns the z-coordinate of the point.
+inline double QwtPoint3D::z() const
+{
+ return d_z;
+}
+
+//! Returns a reference to the x-coordinate of the point.
+inline double &QwtPoint3D::rx()
+{
+ return d_x;
+}
+
+//! Returns a reference to the y-coordinate of the point.
+inline double &QwtPoint3D::ry()
+{
+ return d_y;
+}
+
+//! Returns a reference to the z-coordinate of the point.
+inline double &QwtPoint3D::rz()
+{
+ return d_z;
+}
+
+//! Sets the x-coordinate of the point to the value specified by x.
+inline void QwtPoint3D::setX( double x )
+{
+ d_x = x;
+}
+
+//! Sets the y-coordinate of the point to the value specified by y.
+inline void QwtPoint3D::setY( double y )
+{
+ d_y = y;
+}
+
+//! Sets the z-coordinate of the point to the value specified by z.
+inline void QwtPoint3D::setZ( double z )
+{
+ d_z = z;
+}
+
+/*!
+ Rounds 2D point, where the z coordinate is dropped.
+*/
+inline QPointF QwtPoint3D::toPoint() const
+{
+ return QPointF( d_x, d_y );
+}
+
+//! Returns true if this point and other are equal; otherwise returns false.
+inline bool QwtPoint3D::operator==( const QwtPoint3D &other ) const
+{
+ return ( d_x == other.d_x ) && ( d_y == other.d_y ) && ( d_z == other.d_z );
+}
+
+//! Returns true if this rect and other are different; otherwise returns false.
+inline bool QwtPoint3D::operator!=( const QwtPoint3D &other ) const
+{
+ return !operator==( other );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_point_polar.cpp b/src/libpcp_qwt/src/qwt_point_polar.cpp
new file mode 100644
index 0000000..83224ee
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_point_polar.cpp
@@ -0,0 +1,114 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
+ * QwtPolar Widget Library
+ * Copyright (C) 2008 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_point_polar.h"
+#include "qwt_math.h"
+
+#if QT_VERSION < 0x040601
+#define qAtan2(y, x) ::atan2(y, x)
+#endif
+
+/*!
+ Convert and assign values from a point in Cartesian coordinates
+
+ \param p Point in Cartesian coordinates
+ \sa setPoint(), toPoint()
+*/
+QwtPointPolar::QwtPointPolar( const QPointF &p )
+{
+ d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) );
+ d_azimuth = qAtan2( p.y(), p.x() );
+}
+
+/*!
+ Convert and assign values from a point in Cartesian coordinates
+ \param p Point in Cartesian coordinates
+*/
+void QwtPointPolar::setPoint( const QPointF &p )
+{
+ d_radius = qSqrt( qwtSqr( p.x() ) + qwtSqr( p.y() ) );
+ d_azimuth = qAtan2( p.y(), p.x() );
+}
+
+/*!
+ Convert and return values in Cartesian coordinates
+
+ \note Invalid or null points will be returned as QPointF(0.0, 0.0)
+ \sa isValid(), isNull()
+*/
+QPointF QwtPointPolar::toPoint() const
+{
+ if ( d_radius <= 0.0 )
+ return QPointF( 0.0, 0.0 );
+
+ const double x = d_radius * qCos( d_azimuth );
+ const double y = d_radius * qSin( d_azimuth );
+
+ return QPointF( x, y );
+}
+
+/*!
+ Returns true if point1 is equal to point2; otherwise returns false.
+
+ Two points are equal to each other if radius and
+ azimuth-coordinates are the same. Points are not equal, when
+ the azimuth differs, but other.azimuth() == azimuth() % (2 * PI).
+
+ \sa normalized()
+*/
+bool QwtPointPolar::operator==( const QwtPointPolar &other ) const
+{
+ return d_radius == other.d_radius && d_azimuth == other.d_azimuth;
+}
+
+/*!
+ Returns true if point1 is not equal to point2; otherwise returns false.
+
+ Two points are equal to each other if radius and
+ azimuth-coordinates are the same. Points are not equal, when
+ the azimuth differs, but other.azimuth() == azimuth() % (2 * PI).
+
+ \sa normalized()
+*/
+bool QwtPointPolar::operator!=( const QwtPointPolar &other ) const
+{
+ return d_radius != other.d_radius || d_azimuth != other.d_azimuth;
+}
+
+/*!
+ Normalize radius and azimuth
+
+ When the radius is < 0.0 it is set to 0.0. The azimuth is
+ a value >= 0.0 and < 2 * M_PI.
+*/
+QwtPointPolar QwtPointPolar::normalized() const
+{
+ const double radius = qMax( d_radius, 0.0 );
+
+ double azimuth = d_azimuth;
+ if ( azimuth < -2.0 * M_PI || azimuth >= 2 * M_PI )
+ azimuth = ::fmod( d_azimuth, 2 * M_PI );
+
+ if ( azimuth < 0.0 )
+ azimuth += 2 * M_PI;
+
+ return QwtPointPolar( azimuth, radius );
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<( QDebug debug, const QwtPointPolar &point )
+{
+ debug.nospace() << "QwtPointPolar("
+ << point.azimuth() << "," << point.radius() << ")";
+
+ return debug.space();
+}
+
+#endif
+
diff --git a/src/libpcp_qwt/src/qwt_point_polar.h b/src/libpcp_qwt/src/qwt_point_polar.h
new file mode 100644
index 0000000..17c8121
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_point_polar.h
@@ -0,0 +1,195 @@
+/* -*- 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
+ *****************************************************************************/
+
+/*! \file */
+#ifndef _QWT_POINT_POLAR_H_
+#define _QWT_POINT_POLAR_H_ 1
+
+#include "qwt_global.h"
+#include "qwt_math.h"
+#include <qpoint.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <qdebug.h>
+#endif
+
+/*!
+ \brief A point in polar coordinates
+
+ In polar coordinates a point is determined by an angle and a distance.
+ See http://en.wikipedia.org/wiki/Polar_coordinate_system
+*/
+
+class QWT_EXPORT QwtPointPolar
+{
+public:
+ QwtPointPolar();
+ QwtPointPolar( double azimuth, double radius );
+ QwtPointPolar( const QwtPointPolar & );
+ QwtPointPolar( const QPointF & );
+
+ void setPoint( const QPointF & );
+ QPointF toPoint() const;
+
+ bool isValid() const;
+ bool isNull() const;
+
+ double radius() const;
+ double azimuth() const;
+
+ double &rRadius();
+ double &rAzimuth();
+
+ void setRadius( double );
+ void setAzimuth( double );
+
+ bool operator==( const QwtPointPolar & ) const;
+ bool operator!=( const QwtPointPolar & ) const;
+
+ QwtPointPolar normalized() const;
+
+private:
+ double d_azimuth;
+ double d_radius;
+};
+
+/*!
+ Constructs a null point, with a radius and azimuth set to 0.0.
+ \sa QPointF::isNull
+*/
+inline QwtPointPolar::QwtPointPolar():
+ d_azimuth( 0.0 ),
+ d_radius( 0.0 )
+{
+}
+
+/*!
+ Constructs a point with coordinates specified by radius and azimuth.
+
+ \param azimuth Azimuth
+ \param radius Radius
+*/
+inline QwtPointPolar::QwtPointPolar( double azimuth, double radius ):
+ d_azimuth( azimuth ),
+ d_radius( radius )
+{
+}
+
+/*!
+ Constructs a point using the values of the point specified.
+ \param other Other point
+*/
+inline QwtPointPolar::QwtPointPolar( const QwtPointPolar &other ):
+ d_azimuth( other.d_azimuth ),
+ d_radius( other.d_radius )
+{
+}
+
+//! Returns true if radius() >= 0.0
+inline bool QwtPointPolar::isValid() const
+{
+ return d_radius >= 0.0;
+}
+
+//! Returns true if radius() >= 0.0
+inline bool QwtPointPolar::isNull() const
+{
+ return d_radius == 0.0;
+}
+
+//! Returns the radius.
+inline double QwtPointPolar::radius() const
+{
+ return d_radius;
+}
+
+//! Returns the azimuth.
+inline double QwtPointPolar::azimuth() const
+{
+ return d_azimuth;
+}
+
+//! Returns the radius.
+inline double &QwtPointPolar::rRadius()
+{
+ return d_radius;
+}
+
+//! Returns the azimuth.
+inline double &QwtPointPolar::rAzimuth()
+{
+ return d_azimuth;
+}
+
+//! Sets the radius to radius.
+inline void QwtPointPolar::setRadius( double radius )
+{
+ d_radius = radius;
+}
+
+//! Sets the atimuth to atimuth.
+inline void QwtPointPolar::setAzimuth( double azimuth )
+{
+ d_azimuth = azimuth;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QWT_EXPORT QDebug operator<<( QDebug, const QwtPointPolar & );
+#endif
+
+inline QPoint qwtPolar2Pos( const QPoint &pole,
+ double radius, double angle )
+{
+ const double x = pole.x() + radius * qCos( angle );
+ const double y = pole.y() - radius * qSin( angle );
+
+ return QPoint( qRound( x ), qRound( y ) );
+}
+
+inline QPoint qwtDegree2Pos( const QPoint &pole,
+ double radius, double angle )
+{
+ return qwtPolar2Pos( pole, radius, angle / 180.0 * M_PI );
+}
+
+inline QPointF qwtPolar2Pos( const QPointF &pole,
+ double radius, double angle )
+{
+ const double x = pole.x() + radius * qCos( angle );
+ const double y = pole.y() - radius * qSin( angle );
+
+ return QPointF( x, y);
+}
+
+inline QPointF qwtDegree2Pos( const QPointF &pole,
+ double radius, double angle )
+{
+ return qwtPolar2Pos( pole, radius, angle / 180.0 * M_PI );
+}
+
+inline QPointF qwtFastPolar2Pos( const QPointF &pole,
+ double radius, double angle )
+{
+#if QT_VERSION < 0x040601
+ const double x = pole.x() + radius * ::cos( angle );
+ const double y = pole.y() - radius * ::sin( angle );
+#else
+ const double x = pole.x() + radius * qFastCos( angle );
+ const double y = pole.y() - radius * qFastSin( angle );
+#endif
+
+ return QPointF( x, y);
+}
+
+inline QPointF qwtFastDegree2Pos( const QPointF &pole,
+ double radius, double angle )
+{
+ return qwtFastPolar2Pos( pole, radius, angle / 180.0 * M_PI );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_raster_data.cpp b/src/libpcp_qwt/src/qwt_raster_data.cpp
new file mode 100644
index 0000000..f148d81
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_raster_data.cpp
@@ -0,0 +1,390 @@
+/* -*- 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_raster_data.h"
+#include "qwt_point_3d.h"
+
+class QwtRasterData::ContourPlane
+{
+public:
+ inline ContourPlane( double z ):
+ d_z( z )
+ {
+ }
+
+ inline bool intersect( const QwtPoint3D vertex[3],
+ QPointF line[2], bool ignoreOnPlane ) const;
+
+ inline double z() const { return d_z; }
+
+private:
+ inline int compare( double z ) const;
+ inline QPointF intersection(
+ const QwtPoint3D& p1, const QwtPoint3D &p2 ) const;
+
+ double d_z;
+};
+
+inline bool QwtRasterData::ContourPlane::intersect(
+ const QwtPoint3D vertex[3], QPointF line[2],
+ bool ignoreOnPlane ) const
+{
+ bool found = true;
+
+ // Are the vertices below (-1), on (0) or above (1) the plan ?
+ const int eq1 = compare( vertex[0].z() );
+ const int eq2 = compare( vertex[1].z() );
+ const int eq3 = compare( vertex[2].z() );
+
+ /*
+ (a) All the vertices lie below the contour level.
+ (b) Two vertices lie below and one on the contour level.
+ (c) Two vertices lie below and one above the contour level.
+ (d) One vertex lies below and two on the contour level.
+ (e) One vertex lies below, one on and one above the contour level.
+ (f) One vertex lies below and two above the contour level.
+ (g) Three vertices lie on the contour level.
+ (h) Two vertices lie on and one above the contour level.
+ (i) One vertex lies on and two above the contour level.
+ (j) All the vertices lie above the contour level.
+ */
+
+ static const int tab[3][3][3] =
+ {
+ // jump table to avoid nested case statements
+ { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } },
+ { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } },
+ { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } }
+ };
+
+ const int edgeType = tab[eq1+1][eq2+1][eq3+1];
+ switch ( edgeType )
+ {
+ case 1:
+ // d(0,0,-1), h(0,0,1)
+ line[0] = vertex[0].toPoint();
+ line[1] = vertex[1].toPoint();
+ break;
+ case 2:
+ // d(-1,0,0), h(1,0,0)
+ line[0] = vertex[1].toPoint();
+ line[1] = vertex[2].toPoint();
+ break;
+ case 3:
+ // d(0,-1,0), h(0,1,0)
+ line[0] = vertex[2].toPoint();
+ line[1] = vertex[0].toPoint();
+ break;
+ case 4:
+ // e(0,-1,1), e(0,1,-1)
+ line[0] = vertex[0].toPoint();
+ line[1] = intersection( vertex[1], vertex[2] );
+ break;
+ case 5:
+ // e(-1,0,1), e(1,0,-1)
+ line[0] = vertex[1].toPoint();
+ line[1] = intersection( vertex[2], vertex[0] );
+ break;
+ case 6:
+ // e(-1,1,0), e(1,0,-1)
+ line[0] = vertex[2].toPoint();
+ line[1] = intersection( vertex[0], vertex[1] );
+ break;
+ case 7:
+ // c(-1,1,-1), f(1,1,-1)
+ line[0] = intersection( vertex[0], vertex[1] );
+ line[1] = intersection( vertex[1], vertex[2] );
+ break;
+ case 8:
+ // c(-1,-1,1), f(1,1,-1)
+ line[0] = intersection( vertex[1], vertex[2] );
+ line[1] = intersection( vertex[2], vertex[0] );
+ break;
+ case 9:
+ // f(-1,1,1), c(1,-1,-1)
+ line[0] = intersection( vertex[2], vertex[0] );
+ line[1] = intersection( vertex[0], vertex[1] );
+ break;
+ case 10:
+ // g(0,0,0)
+ // The CONREC algorithm has no satisfying solution for
+ // what to do, when all vertices are on the plane.
+
+ if ( ignoreOnPlane )
+ found = false;
+ else
+ {
+ line[0] = vertex[2].toPoint();
+ line[1] = vertex[0].toPoint();
+ }
+ break;
+ default:
+ found = false;
+ }
+
+ return found;
+}
+
+inline int QwtRasterData::ContourPlane::compare( double z ) const
+{
+ if ( z > d_z )
+ return 1;
+
+ if ( z < d_z )
+ return -1;
+
+ return 0;
+}
+
+inline QPointF QwtRasterData::ContourPlane::intersection(
+ const QwtPoint3D& p1, const QwtPoint3D &p2 ) const
+{
+ const double h1 = p1.z() - d_z;
+ const double h2 = p2.z() - d_z;
+
+ const double x = ( h2 * p1.x() - h1 * p2.x() ) / ( h2 - h1 );
+ const double y = ( h2 * p1.y() - h1 * p2.y() ) / ( h2 - h1 );
+
+ return QPointF( x, y );
+}
+
+//! Constructor
+QwtRasterData::QwtRasterData()
+{
+}
+
+//! Destructor
+QwtRasterData::~QwtRasterData()
+{
+}
+
+/*!
+ Set the bounding interval for the x, y or z coordinates.
+
+ \param axis Axis
+ \param interval Bounding interval
+
+ \sa interval()
+*/
+void QwtRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval )
+{
+ d_intervals[axis] = interval;
+}
+
+/*!
+ \brief Initialize a raster
+
+ Before the composition of an image QwtPlotSpectrogram calls initRaster,
+ announcing the area and its resolution that will be requested.
+
+ The default implementation does nothing, but for data sets that
+ are stored in files, it might be good idea to reimplement initRaster,
+ where the data is resampled and loaded into memory.
+
+ \param area Area of the raster
+ \param raster Number of horizontal and vertical pixels
+
+ \sa initRaster(), value()
+*/
+void QwtRasterData::initRaster( const QRectF &area, const QSize &raster )
+{
+ Q_UNUSED( area );
+ Q_UNUSED( raster );
+}
+
+/*!
+ \brief Discard a raster
+
+ After the composition of an image QwtPlotSpectrogram calls discardRaster().
+
+ The default implementation does nothing, but if data has been loaded
+ in initRaster(), it could deleted now.
+
+ \sa initRaster(), value()
+*/
+void QwtRasterData::discardRaster()
+{
+}
+
+/*!
+ \brief 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.
+
+ Width and height of the hint need to be the horizontal
+ and vertical distances between 2 neighboured points.
+ The center of the hint has to be the position of any point
+ ( it doesn't matter which one ).
+
+ An empty hint indicates, that there are values for any detail level.
+
+ Limiting the resolution of the image might significantly improve
+ the performance and heavily reduce the amount of memory when rendering
+ a QImage from the raster data.
+
+ The default implementation returns an empty rectangle recommending
+ to render in target device ( f.e. screen ) resolution.
+
+ \param area In most implementations the resolution of the data doesn't
+ depend on the requested area.
+
+ \return Bounding rectangle of a pixel
+*/
+QRectF QwtRasterData::pixelHint( const QRectF &area ) const
+{
+ Q_UNUSED( area );
+ return QRectF();
+}
+
+/*!
+ Calculate contour lines
+
+ An adaption of CONREC, a simple contouring algorithm.
+ http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/
+*/
+QwtRasterData::ContourLines QwtRasterData::contourLines(
+ const QRectF &rect, const QSize &raster,
+ const QList<double> &levels, ConrecFlags flags ) const
+{
+ ContourLines contourLines;
+
+ if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() )
+ return contourLines;
+
+ const double dx = rect.width() / raster.width();
+ const double dy = rect.height() / raster.height();
+
+ const bool ignoreOnPlane =
+ flags & QwtRasterData::IgnoreAllVerticesOnLevel;
+
+ const QwtInterval range = interval( Qt::ZAxis );
+ bool ignoreOutOfRange = false;
+ if ( range.isValid() )
+ ignoreOutOfRange = flags & IgnoreOutOfRange;
+
+ QwtRasterData *that = const_cast<QwtRasterData *>( this );
+ that->initRaster( rect, raster );
+
+ for ( int y = 0; y < raster.height() - 1; y++ )
+ {
+ enum Position
+ {
+ Center,
+
+ TopLeft,
+ TopRight,
+ BottomRight,
+ BottomLeft,
+
+ NumPositions
+ };
+
+ QwtPoint3D xy[NumPositions];
+
+ for ( int x = 0; x < raster.width() - 1; x++ )
+ {
+ const QPointF pos( rect.x() + x * dx, rect.y() + y * dy );
+
+ if ( x == 0 )
+ {
+ xy[TopRight].setX( pos.x() );
+ xy[TopRight].setY( pos.y() );
+ xy[TopRight].setZ(
+ value( xy[TopRight].x(), xy[TopRight].y() )
+ );
+
+ xy[BottomRight].setX( pos.x() );
+ xy[BottomRight].setY( pos.y() + dy );
+ xy[BottomRight].setZ(
+ value( xy[BottomRight].x(), xy[BottomRight].y() )
+ );
+ }
+
+ xy[TopLeft] = xy[TopRight];
+ xy[BottomLeft] = xy[BottomRight];
+
+ xy[TopRight].setX( pos.x() + dx );
+ xy[TopRight].setY( pos.y() );
+ xy[BottomRight].setX( pos.x() + dx );
+ xy[BottomRight].setY( pos.y() + dy );
+
+ xy[TopRight].setZ(
+ value( xy[TopRight].x(), xy[TopRight].y() )
+ );
+ xy[BottomRight].setZ(
+ value( xy[BottomRight].x(), xy[BottomRight].y() )
+ );
+
+ double zMin = xy[TopLeft].z();
+ double zMax = zMin;
+ double zSum = zMin;
+
+ for ( int i = TopRight; i <= BottomLeft; i++ )
+ {
+ const double z = xy[i].z();
+
+ zSum += z;
+ if ( z < zMin )
+ zMin = z;
+ if ( z > zMax )
+ zMax = z;
+ }
+
+ if ( ignoreOutOfRange )
+ {
+ if ( !range.contains( zMin ) || !range.contains( zMax ) )
+ continue;
+ }
+
+ if ( zMax < levels[0] ||
+ zMin > levels[levels.size() - 1] )
+ {
+ continue;
+ }
+
+ xy[Center].setX( pos.x() + 0.5 * dx );
+ xy[Center].setY( pos.y() + 0.5 * dy );
+ xy[Center].setZ( 0.25 * zSum );
+
+ const int numLevels = levels.size();
+ for ( int l = 0; l < numLevels; l++ )
+ {
+ const double level = levels[l];
+ if ( level < zMin || level > zMax )
+ continue;
+ QPolygonF &lines = contourLines[level];
+ const ContourPlane plane( level );
+
+ QPointF line[2];
+ QwtPoint3D vertex[3];
+
+ for ( int m = TopLeft; m < NumPositions; m++ )
+ {
+ vertex[0] = xy[m];
+ vertex[1] = xy[0];
+ vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft];
+
+ const bool intersects =
+ plane.intersect( vertex, line, ignoreOnPlane );
+ if ( intersects )
+ {
+ lines += line[0];
+ lines += line[1];
+ }
+ }
+ }
+ }
+ }
+
+ that->discardRaster();
+
+ return contourLines;
+}
diff --git a/src/libpcp_qwt/src/qwt_raster_data.h b/src/libpcp_qwt/src/qwt_raster_data.h
new file mode 100644
index 0000000..d8016c9
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_raster_data.h
@@ -0,0 +1,95 @@
+/* -*- 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_RASTER_DATA_H
+#define QWT_RASTER_DATA_H 1
+
+#include "qwt_global.h"
+#include "qwt_interval.h"
+#include <qmap.h>
+#include <qlist.h>
+#include <qpolygon.h>
+
+class QwtScaleMap;
+
+/*!
+ \brief QwtRasterData defines an interface to any type of raster data.
+
+ QwtRasterData is an abstract interface, that is used by
+ QwtPlotRasterItem to find the values at the pixels of its raster.
+
+ Often a raster item is used to display values from a matrix. Then the
+ derived raster data class needs to implement some sort of resampling,
+ that maps the raster of the matrix into the requested raster of
+ the raster item ( depending on resolution and scales of the canvas ).
+*/
+class QWT_EXPORT QwtRasterData
+{
+public:
+ //! Contour lines
+ typedef QMap<double, QPolygonF> ContourLines;
+
+ //! Flags to modify the contour algorithm
+ enum ConrecFlag
+ {
+ //! Ignore all verices on the same level
+ IgnoreAllVerticesOnLevel = 0x01,
+
+ //! Ignore all values, that are out of range
+ IgnoreOutOfRange = 0x02
+ };
+
+ //! Flags to modify the contour algorithm
+ typedef QFlags<ConrecFlag> ConrecFlags;
+
+ QwtRasterData();
+ virtual ~QwtRasterData();
+
+ virtual void setInterval( Qt::Axis, const QwtInterval & );
+ const QwtInterval &interval(Qt::Axis) const;
+
+ virtual QRectF pixelHint( const QRectF & ) const;
+
+ virtual void initRaster( const QRectF &, const QSize& raster );
+ virtual void discardRaster();
+
+ /*!
+ \return the value at a raster position
+ \param x X value in plot coordinates
+ \param y Y value in plot coordinates
+ */
+ virtual double value( double x, double y ) const = 0;
+
+ virtual ContourLines contourLines( const QRectF &rect,
+ const QSize &raster, const QList<double> &levels,
+ ConrecFlags ) const;
+
+ class Contour3DPoint;
+ class ContourPlane;
+
+private:
+ // Disabled copy constructor and operator=
+ QwtRasterData( const QwtRasterData & );
+ QwtRasterData &operator=( const QwtRasterData & );
+
+ QwtInterval d_intervals[3];
+};
+
+/*!
+ \return Bounding interval for a axis
+ \sa setInterval
+*/
+inline const QwtInterval &QwtRasterData::interval( Qt::Axis axis) const
+{
+ return d_intervals[axis];
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtRasterData::ConrecFlags )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_round_scale_draw.cpp b/src/libpcp_qwt/src/qwt_round_scale_draw.cpp
new file mode 100644
index 0000000..e59192b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_round_scale_draw.cpp
@@ -0,0 +1,309 @@
+/* -*- 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_round_scale_draw.h"
+#include "qwt_painter.h"
+#include "qwt_scale_div.h"
+#include "qwt_scale_map.h"
+#include <qpen.h>
+#include <qpainter.h>
+#include <qfontmetrics.h>
+#include <qmath.h>
+
+class QwtRoundScaleDraw::PrivateData
+{
+public:
+ PrivateData():
+ center( 50.0, 50.0 ),
+ radius( 50.0 ),
+ startAngle( -135 * 16 ),
+ endAngle( 135 * 16 )
+ {
+ }
+
+ QPointF center;
+ double radius;
+
+ double startAngle;
+ double endAngle;
+};
+
+/*!
+ \brief Constructor
+
+ The range of the scale is initialized to [0, 100],
+ The center is set to (50, 50) with a radius of 50.
+ The angle range is set to [-135, 135].
+*/
+QwtRoundScaleDraw::QwtRoundScaleDraw()
+{
+ d_data = new QwtRoundScaleDraw::PrivateData;
+
+ setRadius( 50 );
+ scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle );
+}
+
+//! Destructor
+QwtRoundScaleDraw::~QwtRoundScaleDraw()
+{
+ delete d_data;
+}
+
+/*!
+ Change of radius the scale
+
+ Radius is the radius of the backbone without ticks and labels.
+
+ \param radius New Radius
+ \sa moveCenter()
+*/
+void QwtRoundScaleDraw::setRadius( int radius )
+{
+ d_data->radius = radius;
+}
+
+/*!
+ Get the radius
+
+ Radius is the radius of the backbone without ticks and labels.
+
+ \sa setRadius(), extent()
+*/
+int QwtRoundScaleDraw::radius() const
+{
+ return qCeil( d_data->radius );
+}
+
+/*!
+ Move the center of the scale draw, leaving the radius unchanged
+
+ \param center New center
+ \sa setRadius()
+*/
+void QwtRoundScaleDraw::moveCenter( const QPointF &center )
+{
+ d_data->center = center;
+}
+
+//! Get the center of the scale
+QPointF QwtRoundScaleDraw::center() const
+{
+ return d_data->center;
+}
+
+/*!
+ \brief Adjust the baseline circle segment for round scales.
+
+ The baseline will be drawn from min(angle1,angle2) to max(angle1, angle2).
+ The default setting is [ -135, 135 ].
+ An angle of 0 degrees corresponds to the 12 o'clock position,
+ and positive angles count in a clockwise direction.
+ \param angle1
+ \param angle2 boundaries of the angle interval in degrees.
+ \warning <ul>
+ <li>The angle range is limited to [-360, 360] degrees. Angles exceeding
+ this range will be clipped.
+ <li>For angles more than 359 degrees above or below min(angle1, angle2),
+ scale marks will not be drawn.
+ <li>If you need a counterclockwise scale, use QwtScaleDiv::setRange
+ </ul>
+*/
+void QwtRoundScaleDraw::setAngleRange( double angle1, double angle2 )
+{
+ angle1 = qBound( -360.0, angle1, 360.0 );
+ angle2 = qBound( -360.0, angle2, 360.0 );
+
+ d_data->startAngle = angle1 * 16.0;
+ d_data->endAngle = angle2 * 16.0;
+
+ if ( d_data->startAngle == d_data->endAngle )
+ {
+ d_data->startAngle -= 1;
+ d_data->endAngle += 1;
+ }
+
+ scaleMap().setPaintInterval( d_data->startAngle, d_data->endAngle );
+}
+
+/*!
+ Draws the label for a major scale tick
+
+ \param painter Painter
+ \param value Value
+
+ \sa drawTick(), drawBackbone()
+*/
+void QwtRoundScaleDraw::drawLabel( QPainter *painter, double value ) const
+{
+ const QwtText label = tickLabel( painter->font(), value );
+ if ( label.isEmpty() )
+ return;
+
+ const double tval = scaleMap().transform( value );
+ if ( ( tval > d_data->startAngle + 359 * 16 )
+ || ( tval < d_data->startAngle - 359 * 16 ) )
+ {
+ return;
+ }
+
+ double radius = d_data->radius;
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ||
+ hasComponent( QwtAbstractScaleDraw::Backbone ) )
+ {
+ radius += spacing();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ radius += tickLength( QwtScaleDiv::MajorTick );
+
+ const QSizeF sz = label.textSize( painter->font() );
+ const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
+
+ const double x = d_data->center.x() +
+ ( radius + sz.width() / 2.0 ) * qSin( arc );
+ const double y = d_data->center.y() -
+ ( radius + sz.height() / 2.0 ) * cos( arc );
+
+ const QRectF r( x - sz.width() / 2, y - sz.height() / 2,
+ sz.width(), sz.height() );
+ label.draw( painter, r );
+}
+
+/*!
+ Draw a tick
+
+ \param painter Painter
+ \param value Value of the tick
+ \param len Lenght of the tick
+
+ \sa drawBackbone(), drawLabel()
+*/
+void QwtRoundScaleDraw::drawTick( QPainter *painter, double value, double len ) const
+{
+ if ( len <= 0 )
+ return;
+
+ const double tval = scaleMap().transform( value );
+
+ const double cx = d_data->center.x();
+ const double cy = d_data->center.y();
+ const double radius = d_data->radius;
+
+ if ( ( tval <= d_data->startAngle + 359 * 16 )
+ || ( tval >= d_data->startAngle - 359 * 16 ) )
+ {
+ const double arc = double( tval ) / 16.0 * M_PI / 180.0;
+
+ const double sinArc = qSin( arc );
+ const double cosArc = qCos( arc );
+
+ const double x1 = cx + radius * sinArc;
+ const double x2 = cx + ( radius + len ) * sinArc;
+ const double y1 = cy - radius * cosArc;
+ const double y2 = cy - ( radius + len ) * cosArc;
+
+ QwtPainter::drawLine( painter, x1, y1, x2, y2 );
+ }
+}
+
+/*!
+ Draws the baseline of the scale
+ \param painter Painter
+
+ \sa drawTick(), drawLabel()
+*/
+void QwtRoundScaleDraw::drawBackbone( QPainter *painter ) const
+{
+ const double deg1 = scaleMap().p1();
+ const double deg2 = scaleMap().p2();
+
+ const int a1 = qRound( qMin( deg1, deg2 ) - 90 * 16 );
+ const int a2 = qRound( qMax( deg1, deg2 ) - 90 * 16 );
+
+ const double radius = d_data->radius;
+ const double x = d_data->center.x() - radius;
+ const double y = d_data->center.y() - radius;
+
+ painter->drawArc( QRectF( x, y, 2 * radius, 2 * radius ),
+ -a2, a2 - a1 + 1 ); // counterclockwise
+}
+
+/*!
+ Calculate the extent of the scale
+
+ The extent is the distance between the baseline to the outermost
+ pixel of the scale draw. radius() + extent() is an upper limit
+ for the radius of the bounding circle.
+
+ \param font Font used for painting the labels
+
+ \sa setMinimumExtent(), minimumExtent()
+ \warning The implemented algo is not too smart and
+ calculates only an upper limit, that might be a
+ few pixels too large
+*/
+double QwtRoundScaleDraw::extent( const QFont &font ) const
+{
+ double d = 0.0;
+
+ if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
+ {
+ const QwtScaleDiv &sd = scaleDiv();
+ const QList<double> &ticks = sd.ticks( QwtScaleDiv::MajorTick );
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ const double value = ticks[i];
+ if ( !sd.contains( value ) )
+ continue;
+
+ const QwtText label = tickLabel( font, value );
+ if ( label.isEmpty() )
+ continue;
+
+ const double tval = scaleMap().transform( value );
+ if ( ( tval < d_data->startAngle + 360 * 16 )
+ && ( tval > d_data->startAngle - 360 * 16 ) )
+ {
+ const double arc = tval / 16.0 / 360.0 * 2 * M_PI;
+
+ const QSizeF sz = label.textSize( font );
+ const double off = qMax( sz.width(), sz.height() );
+
+ double x = off * qSin( arc );
+ double y = off * qCos( arc );
+
+ const double dist = qSqrt( x * x + y * y );
+ if ( dist > d )
+ d = dist;
+ }
+ }
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ {
+ d += maxTickLength();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
+ {
+ const double pw = qMax( 1, penWidth() ); // penwidth can be zero
+ d += pw;
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Labels ) &&
+ ( hasComponent( QwtAbstractScaleDraw::Ticks ) ||
+ hasComponent( QwtAbstractScaleDraw::Backbone ) ) )
+ {
+ d += spacing();
+ }
+
+ d = qMax( d, minimumExtent() );
+
+ return d;
+}
diff --git a/src/libpcp_qwt/src/qwt_round_scale_draw.h b/src/libpcp_qwt/src/qwt_round_scale_draw.h
new file mode 100644
index 0000000..9e02060
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_round_scale_draw.h
@@ -0,0 +1,68 @@
+/* -*- 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_ROUND_SCALE_DRAW_H
+#define QWT_ROUND_SCALE_DRAW_H
+
+#include "qwt_global.h"
+#include "qwt_abstract_scale_draw.h"
+#include <qpoint.h>
+
+class QPen;
+
+/*!
+ \brief A class for drawing round scales
+
+ QwtRoundScaleDraw can be used to draw round scales.
+ The circle segment can be adjusted by QwtRoundScaleDraw::setAngleRange().
+ The geometry of the scale can be specified with
+ QwtRoundScaleDraw::moveCenter() and QwtRoundScaleDraw::setRadius().
+
+ After a scale division has been specified as a QwtScaleDiv object
+ using QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s),
+ the scale can be drawn with the QwtAbstractScaleDraw::draw() member.
+*/
+
+class QWT_EXPORT QwtRoundScaleDraw: public QwtAbstractScaleDraw
+{
+public:
+ QwtRoundScaleDraw();
+ virtual ~QwtRoundScaleDraw();
+
+ void setRadius( int radius );
+ int radius() const;
+
+ void moveCenter( double x, double y );
+ void moveCenter( const QPointF & );
+ QPointF center() const;
+
+ void setAngleRange( double angle1, double angle2 );
+
+ virtual double extent( const QFont & ) const;
+
+protected:
+ virtual void drawTick( QPainter *p, double val, double len ) const;
+ virtual void drawBackbone( QPainter *p ) const;
+ virtual void drawLabel( QPainter *p, double val ) const;
+
+private:
+ QwtRoundScaleDraw( const QwtRoundScaleDraw & );
+ QwtRoundScaleDraw &operator=( const QwtRoundScaleDraw &other );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+//! Move the center of the scale draw, leaving the radius unchanged
+inline void QwtRoundScaleDraw::moveCenter( double x, double y )
+{
+ moveCenter( QPointF( x, y ) );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_sampling_thread.cpp b/src/libpcp_qwt/src/qwt_sampling_thread.cpp
new file mode 100644
index 0000000..4cffb3d
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_sampling_thread.cpp
@@ -0,0 +1,106 @@
+/* -*- 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_sampling_thread.h"
+#include "qwt_system_clock.h"
+
+class QwtSamplingThread::PrivateData
+{
+public:
+ QwtSystemClock clock;
+
+ double interval;
+ bool isStopped;
+};
+
+
+//! Constructor
+QwtSamplingThread::QwtSamplingThread( QObject *parent ):
+ QThread( parent )
+{
+ d_data = new PrivateData;
+ d_data->interval = 1000; // 1 second
+ d_data->isStopped = true;
+}
+
+//! Destructor
+QwtSamplingThread::~QwtSamplingThread()
+{
+ delete d_data;
+}
+
+/*!
+ Change the interval (in ms), when sample() is called.
+ The default interval is 1000.0 ( = 1s )
+
+ \param interval Interval
+ \sa interval()
+*/
+void QwtSamplingThread::setInterval( double interval )
+{
+ if ( interval < 0.0 )
+ interval = 0.0;
+
+ d_data->interval = interval;
+}
+
+/*!
+ \return Interval (in ms), between 2 calls of sample()
+ \sa setInterval()
+*/
+double QwtSamplingThread::interval() const
+{
+ return d_data->interval;
+}
+
+/*!
+ \return Time (in ms) since the thread was started
+ \sa QThread::start(), run()
+*/
+double QwtSamplingThread::elapsed() const
+{
+ if ( d_data->isStopped )
+ return 0.0;
+
+ return d_data->clock.elapsed();
+}
+
+/*!
+ Terminate the collecting thread
+ \sa QThread::start(), run()
+*/
+void QwtSamplingThread::stop()
+{
+ d_data->isStopped = true;
+}
+
+/*!
+ Loop collecting samples started from QThread::start()
+ \sa stop()
+*/
+void QwtSamplingThread::run()
+{
+ d_data->clock.start();
+ d_data->isStopped = false;
+
+ while ( !d_data->isStopped )
+ {
+ const double elapsed = d_data->clock.elapsed();
+ sample( elapsed / 1000.0 );
+
+ if ( d_data->interval > 0.0 )
+ {
+ const double msecs =
+ d_data->interval - ( d_data->clock.elapsed() - elapsed );
+
+ if ( msecs > 0.0 )
+ usleep( qRound( 1000.0 * msecs ) );
+ }
+ }
+}
diff --git a/src/libpcp_qwt/src/qwt_sampling_thread.h b/src/libpcp_qwt/src/qwt_sampling_thread.h
new file mode 100644
index 0000000..85b876e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_sampling_thread.h
@@ -0,0 +1,50 @@
+#ifndef _QWT_SAMPLING_THREAD_H_
+#define _QWT_SAMPLING_THREAD_H_
+
+#include "qwt_global.h"
+#include <qthread.h>
+
+/*!
+ \brief A thread collecting samples at regular intervals.
+
+ Contiounous signals are converted into a discrete signal by
+ collecting samples at regular intervals. A discrete signal
+ can be displayed by a QwtPlotSeriesItem on a QwtPlot widget.
+
+ QwtSamplingThread starts a thread calling perodically sample(),
+ to collect and store ( or emit ) a single sample.
+
+ \sa QwtPlotCurve, QwtPlotSeriesItem
+*/
+class QWT_EXPORT QwtSamplingThread: public QThread
+{
+ Q_OBJECT
+
+public:
+ virtual ~QwtSamplingThread();
+
+ double interval() const;
+ double elapsed() const;
+
+public Q_SLOTS:
+ void setInterval( double interval );
+ void stop();
+
+protected:
+ explicit QwtSamplingThread( QObject *parent = NULL );
+
+ virtual void run();
+
+ /*!
+ Collect a sample
+
+ \param elapsed Time since the thread was started in miliseconds
+ */
+ virtual void sample( double elapsed ) = 0;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_div.cpp b/src/libpcp_qwt/src/qwt_scale_div.cpp
new file mode 100644
index 0000000..fab2bcc
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_div.cpp
@@ -0,0 +1,173 @@
+/* -*- 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_scale_div.h"
+#include "qwt_math.h"
+#include "qwt_interval.h"
+#include <qalgorithms.h>
+
+//! Construct an invalid QwtScaleDiv instance.
+QwtScaleDiv::QwtScaleDiv():
+ d_lowerBound( 0.0 ),
+ d_upperBound( 0.0 ),
+ d_isValid( false )
+{
+}
+
+/*!
+ Construct QwtScaleDiv instance.
+
+ \param interval Interval
+ \param ticks List of major, medium and minor ticks
+*/
+QwtScaleDiv::QwtScaleDiv( const QwtInterval &interval,
+ QList<double> ticks[NTickTypes] ):
+ d_lowerBound( interval.minValue() ),
+ d_upperBound( interval.maxValue() ),
+ d_isValid( true )
+{
+ for ( int i = 0; i < NTickTypes; i++ )
+ d_ticks[i] = ticks[i];
+}
+
+/*!
+ Construct QwtScaleDiv instance.
+
+ \param lowerBound First interval limit
+ \param upperBound Second interval limit
+ \param ticks List of major, medium and minor ticks
+*/
+QwtScaleDiv::QwtScaleDiv(
+ double lowerBound, double upperBound,
+ QList<double> ticks[NTickTypes] ):
+ d_lowerBound( lowerBound ),
+ d_upperBound( upperBound ),
+ d_isValid( true )
+{
+ for ( int i = 0; i < NTickTypes; i++ )
+ d_ticks[i] = ticks[i];
+}
+
+/*!
+ Change the interval
+ \param interval Interval
+*/
+void QwtScaleDiv::setInterval( const QwtInterval &interval )
+{
+ setInterval( interval.minValue(), interval.maxValue() );
+}
+
+/*!
+ \brief Equality operator
+ \return true if this instance is equal to other
+*/
+bool QwtScaleDiv::operator==( const QwtScaleDiv &other ) const
+{
+ if ( d_lowerBound != other.d_lowerBound ||
+ d_upperBound != other.d_upperBound ||
+ d_isValid != other.d_isValid )
+ {
+ return false;
+ }
+
+ for ( int i = 0; i < NTickTypes; i++ )
+ {
+ if ( d_ticks[i] != other.d_ticks[i] )
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ \brief Inequality
+ \return true if this instance is not equal to s
+*/
+bool QwtScaleDiv::operator!=( const QwtScaleDiv &s ) const
+{
+ return ( !( *this == s ) );
+}
+
+//! Invalidate the scale division
+void QwtScaleDiv::invalidate()
+{
+ d_isValid = false;
+
+ // detach arrays
+ for ( int i = 0; i < NTickTypes; i++ )
+ d_ticks[i].clear();
+
+ d_lowerBound = d_upperBound = 0;
+}
+
+//! Check if the scale division is valid
+bool QwtScaleDiv::isValid() const
+{
+ return d_isValid;
+}
+
+/*!
+ Return if a value is between lowerBound() and upperBound()
+
+ \param value Value
+ \return true/false
+*/
+bool QwtScaleDiv::contains( double value ) const
+{
+ if ( !d_isValid )
+ return false;
+
+ const double min = qMin( d_lowerBound, d_upperBound );
+ const double max = qMax( d_lowerBound, d_upperBound );
+
+ return value >= min && value <= max;
+}
+
+//! Invert the scale divison
+void QwtScaleDiv::invert()
+{
+ qSwap( d_lowerBound, d_upperBound );
+
+ for ( int i = 0; i < NTickTypes; i++ )
+ {
+ QList<double>& ticks = d_ticks[i];
+
+ const int size = ticks.count();
+ const int size2 = size / 2;
+
+ for ( int i = 0; i < size2; i++ )
+ qSwap( ticks[i], ticks[size - 1 - i] );
+ }
+}
+
+/*!
+ Assign ticks
+
+ \param type MinorTick, MediumTick or MajorTick
+ \param ticks Values of the tick positions
+*/
+void QwtScaleDiv::setTicks( int type, const QList<double> &ticks )
+{
+ if ( type >= 0 && type < NTickTypes )
+ d_ticks[type] = ticks;
+}
+
+/*!
+ Return a list of ticks
+
+ \param type MinorTick, MediumTick or MajorTick
+*/
+const QList<double> &QwtScaleDiv::ticks( int type ) const
+{
+ if ( type >= 0 && type < NTickTypes )
+ return d_ticks[type];
+
+ static QList<double> noTicks;
+ return noTicks;
+}
diff --git a/src/libpcp_qwt/src/qwt_scale_div.h b/src/libpcp_qwt/src/qwt_scale_div.h
new file mode 100644
index 0000000..fee0824
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_div.h
@@ -0,0 +1,132 @@
+/* -*- 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_SCALE_DIV_H
+#define QWT_SCALE_DIV_H
+
+#include "qwt_global.h"
+#include "qwt_interval.h"
+#include <qlist.h>
+
+class QwtInterval;
+
+/*!
+ \brief A class representing a scale division
+
+ A scale division consists of its limits and 3 list
+ of tick values qualified as major, medium and minor ticks.
+
+ In most cases scale divisions are calculated by a QwtScaleEngine.
+
+ \sa subDivideInto(), subDivide()
+*/
+
+class QWT_EXPORT QwtScaleDiv
+{
+public:
+ //! Scale tick types
+ enum TickType
+ {
+ //! No ticks
+ NoTick = -1,
+
+ //! Minor ticks
+ MinorTick,
+
+ //! Medium ticks
+ MediumTick,
+
+ //! Major ticks
+ MajorTick,
+
+ //! Number of valid tick types
+ NTickTypes
+ };
+
+ explicit QwtScaleDiv();
+ explicit QwtScaleDiv( const QwtInterval &, QList<double>[NTickTypes] );
+ explicit QwtScaleDiv(
+ double lowerBound, double upperBound, QList<double>[NTickTypes] );
+
+ bool operator==( const QwtScaleDiv &s ) const;
+ bool operator!=( const QwtScaleDiv &s ) const;
+
+ void setInterval( double lowerBound, double upperBound );
+ void setInterval( const QwtInterval & );
+ QwtInterval interval() const;
+
+ double lowerBound() const;
+ double upperBound() const;
+ double range() const;
+
+ bool contains( double v ) const;
+
+ void setTicks( int type, const QList<double> & );
+ const QList<double> &ticks( int type ) const;
+
+ void invalidate();
+ bool isValid() const;
+
+ void invert();
+
+private:
+ double d_lowerBound;
+ double d_upperBound;
+ QList<double> d_ticks[NTickTypes];
+
+ bool d_isValid;
+};
+
+Q_DECLARE_TYPEINFO(QwtScaleDiv, Q_MOVABLE_TYPE);
+
+/*!
+ Change the interval
+ \param lowerBound lower bound
+ \param upperBound upper bound
+*/
+inline void QwtScaleDiv::setInterval( double lowerBound, double upperBound )
+{
+ d_lowerBound = lowerBound;
+ d_upperBound = upperBound;
+}
+
+/*!
+ \return lowerBound -> upperBound
+*/
+inline QwtInterval QwtScaleDiv::interval() const
+{
+ return QwtInterval( d_lowerBound, d_upperBound );
+}
+
+/*!
+ \return lower bound
+ \sa upperBound()
+*/
+inline double QwtScaleDiv::lowerBound() const
+{
+ return d_lowerBound;
+}
+
+/*!
+ \return upper bound
+ \sa lowerBound()
+*/
+inline double QwtScaleDiv::upperBound() const
+{
+ return d_upperBound;
+}
+
+/*!
+ \return upperBound() - lowerBound()
+*/
+inline double QwtScaleDiv::range() const
+{
+ return d_upperBound - d_lowerBound;
+}
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_draw.cpp b/src/libpcp_qwt/src/qwt_scale_draw.cpp
new file mode 100644
index 0000000..9a9b05b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_draw.cpp
@@ -0,0 +1,903 @@
+/* -*- 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_scale_draw.h"
+#include "qwt_scale_div.h"
+#include "qwt_scale_map.h"
+#include "qwt_math.h"
+#include "qwt_painter.h"
+#include <qpen.h>
+#include <qpainter.h>
+#include <qmath.h>
+
+#if QT_VERSION < 0x040601
+#define qFastSin(x) qSin(x)
+#define qFastCos(x) qCos(x)
+#endif
+
+class QwtScaleDraw::PrivateData
+{
+public:
+ PrivateData():
+ len( 0 ),
+ alignment( QwtScaleDraw::BottomScale ),
+ labelAlignment( 0 ),
+ labelRotation( 0.0 )
+ {
+ }
+
+ QPointF pos;
+ double len;
+
+ Alignment alignment;
+
+ Qt::Alignment labelAlignment;
+ double labelRotation;
+};
+
+/*!
+ \brief Constructor
+
+ The range of the scale is initialized to [0, 100],
+ The position is at (0, 0) with a length of 100.
+ The orientation is QwtAbstractScaleDraw::Bottom.
+*/
+QwtScaleDraw::QwtScaleDraw()
+{
+ d_data = new QwtScaleDraw::PrivateData;
+ setLength( 100 );
+}
+
+//! Destructor
+QwtScaleDraw::~QwtScaleDraw()
+{
+ delete d_data;
+}
+
+/*!
+ Return alignment of the scale
+ \sa setAlignment()
+*/
+QwtScaleDraw::Alignment QwtScaleDraw::alignment() const
+{
+ return d_data->alignment;
+}
+
+/*!
+ Set the alignment of the scale
+
+ The default alignment is QwtScaleDraw::BottomScale
+ \sa alignment()
+*/
+void QwtScaleDraw::setAlignment( Alignment align )
+{
+ d_data->alignment = align;
+}
+
+/*!
+ Return the orientation
+
+ TopScale, BottomScale are horizontal (Qt::Horizontal) scales,
+ LeftScale, RightScale are vertical (Qt::Vertical) scales.
+
+ \sa alignment()
+*/
+Qt::Orientation QwtScaleDraw::orientation() const
+{
+ switch ( d_data->alignment )
+ {
+ case TopScale:
+ case BottomScale:
+ return Qt::Horizontal;
+ case LeftScale:
+ case RightScale:
+ default:
+ return Qt::Vertical;
+ }
+}
+
+/*!
+ \brief Determine the minimum border distance
+
+ This member function returns the minimum space
+ needed to draw the mark labels at the scale's endpoints.
+
+ \param font Font
+ \param start Start border distance
+ \param end End border distance
+*/
+void QwtScaleDraw::getBorderDistHint( const QFont &font,
+ int &start, int &end ) const
+{
+ start = 0;
+ end = 0;
+
+ if ( !hasComponent( QwtAbstractScaleDraw::Labels ) )
+ return;
+
+ const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
+ if ( ticks.count() == 0 )
+ return;
+
+ // Find the ticks, that are mapped to the borders.
+ // minTick is the tick, that is mapped to the top/left-most position
+ // in widget coordinates.
+
+ double minTick = ticks[0];
+ double minPos = scaleMap().transform( minTick );
+ double maxTick = minTick;
+ double maxPos = minPos;
+
+ for ( int i = 1; i < ticks.count(); i++ )
+ {
+ const double tickPos = scaleMap().transform( ticks[i] );
+ if ( tickPos < minPos )
+ {
+ minTick = ticks[i];
+ minPos = tickPos;
+ }
+ if ( tickPos > scaleMap().transform( maxTick ) )
+ {
+ maxTick = ticks[i];
+ maxPos = tickPos;
+ }
+ }
+
+ double e = 0.0;
+ double s = 0.0;
+ if ( orientation() == Qt::Vertical )
+ {
+ s = -labelRect( font, minTick ).top();
+ s -= qAbs( minPos - qRound( scaleMap().p2() ) );
+
+ e = labelRect( font, maxTick ).bottom();
+ e -= qAbs( maxPos - scaleMap().p1() );
+ }
+ else
+ {
+ s = -labelRect( font, minTick ).left();
+ s -= qAbs( minPos - scaleMap().p1() );
+
+ e = labelRect( font, maxTick ).right();
+ e -= qAbs( maxPos - scaleMap().p2() );
+ }
+
+ if ( s < 0.0 )
+ s = 0.0;
+ if ( e < 0.0 )
+ e = 0.0;
+
+ start = qCeil( s );
+ end = qCeil( e );
+}
+
+/*!
+ Determine the minimum distance between two labels, that is necessary
+ that the texts don't overlap.
+
+ \param font Font
+ \return The maximum width of a label
+
+ \sa getBorderDistHint()
+*/
+
+int QwtScaleDraw::minLabelDist( const QFont &font ) const
+{
+ if ( !hasComponent( QwtAbstractScaleDraw::Labels ) )
+ return 0;
+
+ const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
+ if ( ticks.isEmpty() )
+ return 0;
+
+ const QFontMetrics fm( font );
+
+ const bool vertical = ( orientation() == Qt::Vertical );
+
+ QRectF bRect1;
+ QRectF bRect2 = labelRect( font, ticks[0] );
+ if ( vertical )
+ {
+ bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() );
+ }
+
+ double maxDist = 0.0;
+
+ for ( int i = 1; i < ticks.count(); i++ )
+ {
+ bRect1 = bRect2;
+ bRect2 = labelRect( font, ticks[i] );
+ if ( vertical )
+ {
+ bRect2.setRect( -bRect2.bottom(), 0.0,
+ bRect2.height(), bRect2.width() );
+ }
+
+ double dist = fm.leading(); // space between the labels
+ if ( bRect1.right() > 0 )
+ dist += bRect1.right();
+ if ( bRect2.left() < 0 )
+ dist += -bRect2.left();
+
+ if ( dist > maxDist )
+ maxDist = dist;
+ }
+
+ double angle = labelRotation() / 180.0 * M_PI;
+ if ( vertical )
+ angle += M_PI / 2;
+
+ const double sinA = qFastSin( angle ); // qreal -> double
+ if ( qFuzzyCompare( sinA + 1.0, 1.0 ) )
+ return qCeil( maxDist );
+
+ const int fmHeight = fm.ascent() - 2;
+
+ // The distance we need until there is
+ // the height of the label font. This height is needed
+ // for the neighbour labal.
+
+ double labelDist = fmHeight / qFastSin( angle ) * qFastCos( angle );
+ if ( labelDist < 0 )
+ labelDist = -labelDist;
+
+ // For text orientations close to the scale orientation
+
+ if ( labelDist > maxDist )
+ labelDist = maxDist;
+
+ // For text orientations close to the opposite of the
+ // scale orientation
+
+ if ( labelDist < fmHeight )
+ labelDist = fmHeight;
+
+ return qCeil( labelDist );
+}
+
+/*!
+ Calculate the width/height that is needed for a
+ vertical/horizontal scale.
+
+ The extent is calculated from the pen width of the backbone,
+ the major tick length, the spacing and the maximum width/height
+ of the labels.
+
+ \param font Font used for painting the labels
+
+ \sa minLength()
+*/
+double QwtScaleDraw::extent( const QFont &font ) const
+{
+ double d = 0;
+
+ if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
+ {
+ if ( orientation() == Qt::Vertical )
+ d = maxLabelWidth( font );
+ else
+ d = maxLabelHeight( font );
+
+ if ( d > 0 )
+ d += spacing();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ {
+ d += maxTickLength();
+ }
+
+ if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
+ {
+ const double pw = qMax( 1, penWidth() ); // penwidth can be zero
+ d += pw;
+ }
+
+ d = qMax( d, minimumExtent() );
+ return d;
+}
+
+/*!
+ Calculate the minimum length that is needed to draw the scale
+
+ \param font Font used for painting the labels
+
+ \sa extent()
+*/
+int QwtScaleDraw::minLength( const QFont &font ) const
+{
+ int startDist, endDist;
+ getBorderDistHint( font, startDist, endDist );
+
+ const QwtScaleDiv &sd = scaleDiv();
+
+ const uint minorCount =
+ sd.ticks( QwtScaleDiv::MinorTick ).count() +
+ sd.ticks( QwtScaleDiv::MediumTick ).count();
+ const uint majorCount =
+ sd.ticks( QwtScaleDiv::MajorTick ).count();
+
+ int lengthForLabels = 0;
+ if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
+ lengthForLabels = minLabelDist( font ) * majorCount;
+
+ int lengthForTicks = 0;
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ {
+ const double pw = qMax( 1, penWidth() ); // penwidth can be zero
+ lengthForTicks = qCeil( ( majorCount + minorCount ) * ( pw + 1.0 ) );
+ }
+
+ return startDist + endDist + qMax( lengthForLabels, lengthForTicks );
+}
+
+/*!
+ Find the position, where to paint a label
+
+ The position has a distance of majTickLength() + spacing() + 1
+ from the backbone. The direction depends on the alignment()
+
+ \param value Value
+*/
+QPointF QwtScaleDraw::labelPosition( double value ) const
+{
+ const double tval = scaleMap().transform( value );
+ double dist = spacing();
+ if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
+ dist += qMax( 1, penWidth() );
+
+ if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
+ dist += tickLength( QwtScaleDiv::MajorTick );
+
+ double px = 0;
+ double py = 0;
+
+ switch ( alignment() )
+ {
+ case RightScale:
+ {
+ px = d_data->pos.x() + dist;
+ py = tval;
+ break;
+ }
+ case LeftScale:
+ {
+ px = d_data->pos.x() - dist;
+ py = tval;
+ break;
+ }
+ case BottomScale:
+ {
+ px = tval;
+ py = d_data->pos.y() + dist;
+ break;
+ }
+ case TopScale:
+ {
+ px = tval;
+ py = d_data->pos.y() - dist;
+ break;
+ }
+ }
+
+ return QPointF( px, py );
+}
+
+/*!
+ Draw a tick
+
+ \param painter Painter
+ \param value Value of the tick
+ \param len Lenght of the tick
+
+ \sa drawBackbone(), drawLabel()
+*/
+void QwtScaleDraw::drawTick( QPainter *painter, double value, double len ) const
+{
+ if ( len <= 0 )
+ return;
+
+ const bool roundingAlignment = QwtPainter::roundingAlignment( painter );
+
+ QPointF pos = d_data->pos;
+
+ double tval = scaleMap().transform( value );
+ if ( roundingAlignment )
+ tval = qRound( tval );
+
+ const int pw = penWidth();
+ int a = 0;
+ if ( pw > 1 && roundingAlignment )
+ a = 1;
+
+ switch ( alignment() )
+ {
+ case LeftScale:
+ {
+ double x1 = pos.x() + a;
+ double x2 = pos.x() + a - pw - len;
+ if ( roundingAlignment )
+ {
+ x1 = qRound( x1 );
+ x2 = qRound( x2 );
+ }
+
+ QwtPainter::drawLine( painter, x1, tval, x2, tval );
+ break;
+ }
+
+ case RightScale:
+ {
+ double x1 = pos.x();
+ double x2 = pos.x() + pw + len;
+ if ( roundingAlignment )
+ {
+ x1 = qRound( x1 );
+ x2 = qRound( x2 );
+ }
+
+ QwtPainter::drawLine( painter, x1, tval, x2, tval );
+ break;
+ }
+
+ case BottomScale:
+ {
+ double y1 = pos.y();
+ double y2 = pos.y() + pw + len;
+ if ( roundingAlignment )
+ {
+ y1 = qRound( y1 );
+ y2 = qRound( y2 );
+ }
+
+ QwtPainter::drawLine( painter, tval, y1, tval, y2 );
+ break;
+ }
+
+ case TopScale:
+ {
+ double y1 = pos.y() + a;
+ double y2 = pos.y() - pw - len + a;
+ if ( roundingAlignment )
+ {
+ y1 = qRound( y1 );
+ y2 = qRound( y2 );
+ }
+
+ QwtPainter::drawLine( painter, tval, y1, tval, y2 );
+ break;
+ }
+ }
+}
+
+/*!
+ Draws the baseline of the scale
+ \param painter Painter
+
+ \sa drawTick(), drawLabel()
+*/
+void QwtScaleDraw::drawBackbone( QPainter *painter ) const
+{
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ const QPointF &pos = d_data->pos;
+ const double len = d_data->len;
+ const int pw = qMax( penWidth(), 1 );
+
+ // pos indicates a border not the center of the backbone line
+ // so we need to shift its position depending on the pen width
+ // and the alignment of the scale
+
+ double off;
+ if ( doAlign )
+ {
+ if ( alignment() == LeftScale || alignment() == TopScale )
+ off = ( pw - 1 ) / 2;
+ else
+ off = pw / 2;
+ }
+ else
+ {
+ off = 0.5 * penWidth();
+ }
+
+ switch ( alignment() )
+ {
+ case LeftScale:
+ {
+ double x = pos.x() - off;
+ if ( doAlign )
+ x = qRound( x );
+
+ QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len );
+ break;
+ }
+ case RightScale:
+ {
+ double x = pos.x() + off;
+ if ( doAlign )
+ x = qRound( x );
+
+ QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len );
+ break;
+ }
+ case TopScale:
+ {
+ double y = pos.y() - off;
+ if ( doAlign )
+ y = qRound( y );
+
+ QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y );
+ break;
+ }
+ case BottomScale:
+ {
+ double y = pos.y() + off;
+ if ( doAlign )
+ y = qRound( y );
+
+ QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y );
+ break;
+ }
+ }
+}
+
+/*!
+ \brief Move the position of the scale
+
+ The meaning of the parameter pos depends on the alignment:
+ <dl>
+ <dt>QwtScaleDraw::LeftScale
+ <dd>The origin is the topmost point of the
+ backbone. The backbone is a vertical line.
+ Scale marks and labels are drawn
+ at the left of the backbone.
+ <dt>QwtScaleDraw::RightScale
+ <dd>The origin is the topmost point of the
+ backbone. The backbone is a vertical line.
+ Scale marks and labels are drawn
+ at the right of the backbone.
+ <dt>QwtScaleDraw::TopScale
+ <dd>The origin is the leftmost point of the
+ backbone. The backbone is a horizontal line.
+ Scale marks and labels are drawn
+ above the backbone.
+ <dt>QwtScaleDraw::BottomScale
+ <dd>The origin is the leftmost point of the
+ backbone. The backbone is a horizontal line
+ Scale marks and labels are drawn
+ below the backbone.
+ </dl>
+
+ \param pos Origin of the scale
+
+ \sa pos(), setLength()
+*/
+void QwtScaleDraw::move( const QPointF &pos )
+{
+ d_data->pos = pos;
+ updateMap();
+}
+
+/*!
+ \return Origin of the scale
+ \sa move(), length()
+*/
+QPointF QwtScaleDraw::pos() const
+{
+ return d_data->pos;
+}
+
+/*!
+ Set the length of the backbone.
+
+ The length doesn't include the space needed for
+ overlapping labels.
+
+ \sa move(), minLabelDist()
+*/
+void QwtScaleDraw::setLength( double length )
+{
+ if ( length >= 0 && length < 10 )
+ length = 10;
+ if ( length < 0 && length > -10 )
+ length = -10;
+
+ d_data->len = length;
+ updateMap();
+}
+
+/*!
+ \return the length of the backbone
+ \sa setLength(), pos()
+*/
+double QwtScaleDraw::length() const
+{
+ return d_data->len;
+}
+
+/*!
+ Draws the label for a major scale tick
+
+ \param painter Painter
+ \param value Value
+
+ \sa drawTick(), drawBackbone(), boundingLabelRect()
+*/
+void QwtScaleDraw::drawLabel( QPainter *painter, double value ) const
+{
+ QwtText lbl = tickLabel( painter->font(), value );
+ if ( lbl.isEmpty() )
+ return;
+
+ QPointF pos = labelPosition( value );
+
+ QSizeF labelSize = lbl.textSize( painter->font() );
+
+ const QTransform transform = labelTransformation( pos, labelSize );
+
+ painter->save();
+ painter->setWorldTransform( transform, true );
+
+ lbl.draw ( painter, QRect( QPoint( 0, 0 ), labelSize.toSize() ) );
+
+ painter->restore();
+}
+
+/*!
+ Find the bounding rect for the label. The coordinates of
+ the rect are absolute coordinates ( calculated from pos() ).
+ in direction of the tick.
+
+ \param font Font used for painting
+ \param value Value
+
+ \sa labelRect()
+*/
+QRect QwtScaleDraw::boundingLabelRect( const QFont &font, double value ) const
+{
+ QwtText lbl = tickLabel( font, value );
+ if ( lbl.isEmpty() )
+ return QRect();
+
+ const QPointF pos = labelPosition( value );
+ QSizeF labelSize = lbl.textSize( font );
+
+ const QTransform transform = labelTransformation( pos, labelSize );
+ return transform.mapRect( QRect( QPoint( 0, 0 ), labelSize.toSize() ) );
+}
+
+/*!
+ Calculate the transformation that is needed to paint a label
+ depending on its alignment and rotation.
+
+ \param pos Position where to paint the label
+ \param size Size of the label
+
+ \sa setLabelAlignment(), setLabelRotation()
+*/
+QTransform QwtScaleDraw::labelTransformation(
+ const QPointF &pos, const QSizeF &size ) const
+{
+ QTransform transform;
+ transform.translate( pos.x(), pos.y() );
+ transform.rotate( labelRotation() );
+
+ int flags = labelAlignment();
+ if ( flags == 0 )
+ {
+ switch ( alignment() )
+ {
+ case RightScale:
+ {
+ if ( flags == 0 )
+ flags = Qt::AlignRight | Qt::AlignVCenter;
+ break;
+ }
+ case LeftScale:
+ {
+ if ( flags == 0 )
+ flags = Qt::AlignLeft | Qt::AlignVCenter;
+ break;
+ }
+ case BottomScale:
+ {
+ if ( flags == 0 )
+ flags = Qt::AlignHCenter | Qt::AlignBottom;
+ break;
+ }
+ case TopScale:
+ {
+ if ( flags == 0 )
+ flags = Qt::AlignHCenter | Qt::AlignTop;
+ break;
+ }
+ }
+ }
+
+ double x, y;
+
+ if ( flags & Qt::AlignLeft )
+ x = -size.width();
+ else if ( flags & Qt::AlignRight )
+ x = 0.0;
+ else // Qt::AlignHCenter
+ x = -( 0.5 * size.width() );
+
+ if ( flags & Qt::AlignTop )
+ y = -size.height();
+ else if ( flags & Qt::AlignBottom )
+ y = 0;
+ else // Qt::AlignVCenter
+ y = -( 0.5 * size.height() );
+
+ transform.translate( x, y );
+
+ return transform;
+}
+
+/*!
+ Find the bounding rect for the label. The coordinates of
+ the rect are relative to spacing + ticklength from the backbone
+ in direction of the tick.
+
+ \param font Font used for painting
+ \param value Value
+*/
+QRectF QwtScaleDraw::labelRect( const QFont &font, double value ) const
+{
+ QwtText lbl = tickLabel( font, value );
+ if ( lbl.isEmpty() )
+ return QRectF( 0.0, 0.0, 0.0, 0.0 );
+
+ const QPointF pos = labelPosition( value );
+
+ const QSizeF labelSize = lbl.textSize( font );
+ const QTransform transform = labelTransformation( pos, labelSize );
+
+ QRectF br = transform.mapRect( QRectF( QPointF( 0, 0 ), labelSize ) );
+ br.translate( -pos.x(), -pos.y() );
+
+ return br;
+}
+
+/*!
+ Calculate the size that is needed to draw a label
+
+ \param font Label font
+ \param value Value
+*/
+QSizeF QwtScaleDraw::labelSize( const QFont &font, double value ) const
+{
+ return labelRect( font, value ).size();
+}
+
+/*!
+ Rotate all labels.
+
+ When changing the rotation, it might be necessary to
+ adjust the label flags too. Finding a useful combination is
+ often the result of try and error.
+
+ \param rotation Angle in degrees. When changing the label rotation,
+ the label flags often needs to be adjusted too.
+
+ \sa setLabelAlignment(), labelRotation(), labelAlignment().
+
+*/
+void QwtScaleDraw::setLabelRotation( double rotation )
+{
+ d_data->labelRotation = rotation;
+}
+
+/*!
+ \return the label rotation
+ \sa setLabelRotation(), labelAlignment()
+*/
+double QwtScaleDraw::labelRotation() const
+{
+ return d_data->labelRotation;
+}
+
+/*!
+ \brief Change the label flags
+
+ Labels are aligned to the point ticklength + spacing away from the backbone.
+
+ The alignment is relative to the orientation of the label text.
+ In case of an flags of 0 the label will be aligned
+ depending on the orientation of the scale:
+
+ QwtScaleDraw::TopScale: Qt::AlignHCenter | Qt::AlignTop\n
+ QwtScaleDraw::BottomScale: Qt::AlignHCenter | Qt::AlignBottom\n
+ QwtScaleDraw::LeftScale: Qt::AlignLeft | Qt::AlignVCenter\n
+ QwtScaleDraw::RightScale: Qt::AlignRight | Qt::AlignVCenter\n
+
+ Changing the alignment is often necessary for rotated labels.
+
+ \param alignment Or'd Qt::AlignmentFlags see <qnamespace.h>
+
+ \sa setLabelRotation(), labelRotation(), labelAlignment()
+ \warning The various alignments might be confusing.
+ The alignment of the label is not the alignment
+ of the scale and is not the alignment of the flags
+ (QwtText::flags()) returned from QwtAbstractScaleDraw::label().
+*/
+
+void QwtScaleDraw::setLabelAlignment( Qt::Alignment alignment )
+{
+ d_data->labelAlignment = alignment;
+}
+
+/*!
+ \return the label flags
+ \sa setLabelAlignment(), labelRotation()
+*/
+Qt::Alignment QwtScaleDraw::labelAlignment() const
+{
+ return d_data->labelAlignment;
+}
+
+/*!
+ \param font Font
+ \return the maximum width of a label
+*/
+int QwtScaleDraw::maxLabelWidth( const QFont &font ) const
+{
+ double maxWidth = 0.0;
+
+ const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ const double v = ticks[i];
+ if ( scaleDiv().contains( v ) )
+ {
+ const double w = labelSize( font, ticks[i] ).width();
+ if ( w > maxWidth )
+ maxWidth = w;
+ }
+ }
+
+ return qCeil( maxWidth );
+}
+
+/*!
+ \param font Font
+ \return the maximum height of a label
+*/
+int QwtScaleDraw::maxLabelHeight( const QFont &font ) const
+{
+ double maxHeight = 0.0;
+
+ const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ const double v = ticks[i];
+ if ( scaleDiv().contains( v ) )
+ {
+ const double h = labelSize( font, ticks[i] ).height();
+ if ( h > maxHeight )
+ maxHeight = h;
+ }
+ }
+
+ return qCeil( maxHeight );
+}
+
+void QwtScaleDraw::updateMap()
+{
+ const QPointF pos = d_data->pos;
+ double len = d_data->len;
+
+ QwtScaleMap &sm = scaleMap();
+ if ( orientation() == Qt::Vertical )
+ sm.setPaintInterval( pos.y() + len, pos.y() );
+ else
+ sm.setPaintInterval( pos.x(), pos.x() + len );
+}
diff --git a/src/libpcp_qwt/src/qwt_scale_draw.h b/src/libpcp_qwt/src/qwt_scale_draw.h
new file mode 100644
index 0000000..8eeb71b
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_draw.h
@@ -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_SCALE_DRAW_H
+#define QWT_SCALE_DRAW_H
+
+#include "qwt_global.h"
+#include "qwt_abstract_scale_draw.h"
+#include <qpoint.h>
+#include <qrect.h>
+#include <qtransform.h>
+
+/*!
+ \brief A class for drawing scales
+
+ QwtScaleDraw can be used to draw linear or logarithmic scales.
+ A scale has a position, an alignment and a length, which can be specified .
+ The labels can be rotated and aligned
+ to the ticks using setLabelRotation() and setLabelAlignment().
+
+ After a scale division has been specified as a QwtScaleDiv object
+ using QwtAbstractScaleDraw::setScaleDiv(const QwtScaleDiv &s),
+ the scale can be drawn with the QwtAbstractScaleDraw::draw() member.
+*/
+
+class QWT_EXPORT QwtScaleDraw: public QwtAbstractScaleDraw
+{
+public:
+ /*!
+ Alignment of the scale draw
+ \sa setAlignment(), alignment()
+ */
+ enum Alignment
+ {
+ //! The scale is below
+ BottomScale,
+
+ //! The scale is above
+ TopScale,
+
+ //! The scale is left
+ LeftScale,
+
+ //! The scale is right
+ RightScale
+ };
+
+ QwtScaleDraw();
+ virtual ~QwtScaleDraw();
+
+ void getBorderDistHint( const QFont &, int &start, int &end ) const;
+ int minLabelDist( const QFont & ) const;
+
+ int minLength( const QFont & ) const;
+ virtual double extent( const QFont & ) const;
+
+ void move( double x, double y );
+ void move( const QPointF & );
+ void setLength( double length );
+
+ Alignment alignment() const;
+ void setAlignment( Alignment );
+
+ Qt::Orientation orientation() const;
+
+ QPointF pos() const;
+ double length() const;
+
+ void setLabelAlignment( Qt::Alignment );
+ Qt::Alignment labelAlignment() const;
+
+ void setLabelRotation( double rotation );
+ double labelRotation() const;
+
+ int maxLabelHeight( const QFont & ) const;
+ int maxLabelWidth( const QFont & ) const;
+
+ QPointF labelPosition( double val ) const;
+
+ QRectF labelRect( const QFont &, double val ) const;
+ QSizeF labelSize( const QFont &, double val ) const;
+
+ QRect boundingLabelRect( const QFont &, double val ) const;
+
+protected:
+ QTransform labelTransformation( const QPointF &, const QSizeF & ) const;
+
+ virtual void drawTick( QPainter *, double val, double len ) const;
+ virtual void drawBackbone( QPainter * ) const;
+ virtual void drawLabel( QPainter *, double val ) const;
+
+private:
+ QwtScaleDraw( const QwtScaleDraw & );
+ QwtScaleDraw &operator=( const QwtScaleDraw &other );
+
+ void updateMap();
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+/*!
+ Move the position of the scale
+ \sa move(const QPointF &)
+*/
+inline void QwtScaleDraw::move( double x, double y )
+{
+ move( QPointF( x, y ) );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_engine.cpp b/src/libpcp_qwt/src/qwt_scale_engine.cpp
new file mode 100644
index 0000000..9e5e97e
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_engine.cpp
@@ -0,0 +1,967 @@
+/* -*- 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_scale_engine.h"
+#include "qwt_math.h"
+#include "qwt_scale_map.h"
+#include <qalgorithms.h>
+#include <qmath.h>
+#include <float.h>
+
+#if QT_VERSION < 0x040601
+#define qFabs(x) ::fabs(x)
+#define qExp(x) ::exp(x)
+#endif
+
+static const double _eps = 1.0e-6;
+
+/*!
+ Ceil a value, relative to an interval
+
+ \param value Value to ceil
+ \param intervalSize Interval size
+
+ \sa floorEps()
+*/
+double QwtScaleArithmetic::ceilEps( double value,
+ double intervalSize )
+{
+ const double eps = _eps * intervalSize;
+
+ value = ( value - eps ) / intervalSize;
+ return ::ceil( value ) * intervalSize;
+}
+
+/*!
+ Floor a value, relative to an interval
+
+ \param value Value to floor
+ \param intervalSize Interval size
+
+ \sa floorEps()
+*/
+double QwtScaleArithmetic::floorEps( double value, double intervalSize )
+{
+ const double eps = _eps * intervalSize;
+
+ value = ( value + eps ) / intervalSize;
+ return ::floor( value ) * intervalSize;
+}
+
+/*!
+ \brief Divide an interval into steps
+
+ \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$
+
+ \param intervalSize Interval size
+ \param numSteps Number of steps
+ \return Step size
+*/
+double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps )
+{
+ if ( numSteps == 0.0 || intervalSize == 0.0 )
+ return 0.0;
+
+ return ( intervalSize - ( _eps * intervalSize ) ) / numSteps;
+}
+
+/*!
+ Find the smallest value out of {1,2,5}*10^n with an integer number n
+ which is greater than or equal to x
+
+ \param x Input value
+*/
+double QwtScaleArithmetic::ceil125( double x )
+{
+ if ( x == 0.0 )
+ return 0.0;
+
+ const double sign = ( x > 0 ) ? 1.0 : -1.0;
+ const double lx = ::log10( qFabs( x ) );
+ const double p10 = ::floor( lx );
+
+ double fr = qPow( 10.0, lx - p10 );
+ if ( fr <= 1.0 )
+ fr = 1.0;
+ else if ( fr <= 2.0 )
+ fr = 2.0;
+ else if ( fr <= 5.0 )
+ fr = 5.0;
+ else
+ fr = 10.0;
+
+ return sign * fr * qPow( 10.0, p10 );
+}
+
+/*!
+ \brief Find the largest value out of {1,2,5}*10^n with an integer number n
+ which is smaller than or equal to x
+
+ \param x Input value
+*/
+double QwtScaleArithmetic::floor125( double x )
+{
+ if ( x == 0.0 )
+ return 0.0;
+
+ double sign = ( x > 0 ) ? 1.0 : -1.0;
+ const double lx = ::log10( qFabs( x ) );
+ const double p10 = ::floor( lx );
+
+ double fr = qPow( 10.0, lx - p10 );
+ if ( fr >= 10.0 )
+ fr = 10.0;
+ else if ( fr >= 5.0 )
+ fr = 5.0;
+ else if ( fr >= 2.0 )
+ fr = 2.0;
+ else
+ fr = 1.0;
+
+ return sign * fr * qPow( 10.0, p10 );
+}
+
+class QwtScaleEngine::PrivateData
+{
+public:
+ PrivateData():
+ attributes( QwtScaleEngine::NoAttribute ),
+ lowerMargin( 0.0 ),
+ upperMargin( 0.0 ),
+ referenceValue( 0.0 )
+ {
+ }
+
+ QwtScaleEngine::Attributes attributes; // scale attributes
+
+ double lowerMargin; // margins
+ double upperMargin;
+
+ double referenceValue; // reference value
+
+};
+
+//! Constructor
+QwtScaleEngine::QwtScaleEngine()
+{
+ d_data = new PrivateData;
+}
+
+
+//! Destructor
+QwtScaleEngine::~QwtScaleEngine ()
+{
+ delete d_data;
+}
+
+/*!
+ \return the margin at the lower end of the scale
+ The default margin is 0.
+
+ \sa setMargins()
+*/
+double QwtScaleEngine::lowerMargin() const
+{
+ return d_data->lowerMargin;
+}
+
+/*!
+ \return the margin at the upper end of the scale
+ The default margin is 0.
+
+ \sa setMargins()
+*/
+double QwtScaleEngine::upperMargin() const
+{
+ return d_data->upperMargin;
+}
+
+/*!
+ \brief Specify margins at the scale's endpoints
+ \param lower minimum distance between the scale's lower boundary and the
+ smallest enclosed value
+ \param upper minimum distance between the scale's upper boundary and the
+ greatest enclosed value
+
+ Margins can be used to leave a minimum amount of space between
+ the enclosed intervals and the boundaries of the scale.
+
+ \warning
+ \li QwtLog10ScaleEngine measures the margins in decades.
+
+ \sa upperMargin(), lowerMargin()
+*/
+
+void QwtScaleEngine::setMargins( double lower, double upper )
+{
+ d_data->lowerMargin = qMax( lower, 0.0 );
+ d_data->upperMargin = qMax( upper, 0.0 );
+}
+
+/*!
+ Calculate a step size for an interval size
+
+ \param intervalSize Interval size
+ \param numSteps Number of steps
+
+ \return Step size
+*/
+double QwtScaleEngine::divideInterval(
+ double intervalSize, int numSteps ) const
+{
+ if ( numSteps <= 0 )
+ return 0.0;
+
+ double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
+ return QwtScaleArithmetic::ceil125( v );
+}
+
+/*!
+ Check if an interval "contains" a value
+
+ \param interval Interval
+ \param value Value
+
+ \sa QwtScaleArithmetic::compareEps()
+*/
+bool QwtScaleEngine::contains(
+ const QwtInterval &interval, double value ) const
+{
+ if ( !interval.isValid() )
+ return false;
+
+ if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 )
+ return false;
+
+ if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 )
+ return false;
+
+ return true;
+}
+
+/*!
+ Remove ticks from a list, that are not inside an interval
+
+ \param ticks Tick list
+ \param interval Interval
+
+ \return Stripped tick list
+*/
+QList<double> QwtScaleEngine::strip( const QList<double>& ticks,
+ const QwtInterval &interval ) const
+{
+ if ( !interval.isValid() || ticks.count() == 0 )
+ return QList<double>();
+
+ if ( contains( interval, ticks.first() )
+ && contains( interval, ticks.last() ) )
+ {
+ return ticks;
+ }
+
+ QList<double> strippedTicks;
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ if ( contains( interval, ticks[i] ) )
+ strippedTicks += ticks[i];
+ }
+ return strippedTicks;
+}
+
+/*!
+ \brief Build an interval for a value
+
+ In case of v == 0.0 the interval is [-0.5, 0.5],
+ otherwide it is [0.5 * v, 1.5 * v]
+*/
+
+QwtInterval QwtScaleEngine::buildInterval( double v ) const
+{
+ const double delta = ( v == 0.0 ) ? 0.5 : qAbs( 0.5 * v );
+
+ if ( DBL_MAX - delta < v )
+ return QwtInterval( DBL_MAX - delta, DBL_MAX );
+
+ if ( -DBL_MAX + delta > v )
+ return QwtInterval( -DBL_MAX, -DBL_MAX + delta );
+
+ return QwtInterval( v - delta, v + delta );
+}
+
+/*!
+ Change a scale attribute
+
+ \param attribute Attribute to change
+ \param on On/Off
+
+ \sa Attribute, testAttribute()
+*/
+void QwtScaleEngine::setAttribute( Attribute attribute, bool on )
+{
+ if ( on )
+ d_data->attributes |= attribute;
+ else
+ d_data->attributes &= ~attribute;
+}
+
+/*!
+ Check if a attribute is set.
+
+ \param attribute Attribute to be tested
+ \sa Attribute, setAttribute()
+*/
+bool QwtScaleEngine::testAttribute( Attribute attribute ) const
+{
+ return ( d_data->attributes & attribute );
+}
+
+/*!
+ Change the scale attribute
+
+ \param attributes Set scale attributes
+ \sa Attribute, attributes()
+*/
+void QwtScaleEngine::setAttributes( Attributes attributes )
+{
+ d_data->attributes = attributes;
+}
+
+/*!
+ Return the scale attributes
+ \sa Attribute, setAttributes(), testAttribute()
+*/
+QwtScaleEngine::Attributes QwtScaleEngine::attributes() const
+{
+ return d_data->attributes;
+}
+
+/*!
+ \brief Specify a reference point
+ \param r new reference value
+
+ The reference point is needed if options IncludeReference or
+ Symmetric are active. Its default value is 0.0.
+
+ \sa Attribute
+*/
+void QwtScaleEngine::setReference( double r )
+{
+ d_data->referenceValue = r;
+}
+
+/*!
+ \return the reference value
+ \sa setReference(), setAttribute()
+*/
+double QwtScaleEngine::reference() const
+{
+ return d_data->referenceValue;
+}
+
+/*!
+ Return a transformation, for linear scales
+*/
+QwtScaleTransformation *QwtLinearScaleEngine::transformation() const
+{
+ return new QwtScaleTransformation( QwtScaleTransformation::Linear );
+}
+
+/*!
+ Align and divide an interval
+
+ \param maxNumSteps Max. number of steps
+ \param x1 First limit of the interval (In/Out)
+ \param x2 Second limit of the interval (In/Out)
+ \param stepSize Step size (Out)
+
+ \sa setAttribute()
+*/
+void QwtLinearScaleEngine::autoScale( int maxNumSteps,
+ double &x1, double &x2, double &stepSize ) const
+{
+ QwtInterval interval( x1, x2 );
+ interval = interval.normalized();
+
+ interval.setMinValue( interval.minValue() - lowerMargin() );
+ interval.setMaxValue( interval.maxValue() + upperMargin() );
+
+ if ( testAttribute( QwtScaleEngine::Symmetric ) )
+ interval = interval.symmetrize( reference() );
+
+ if ( testAttribute( QwtScaleEngine::IncludeReference ) )
+ interval = interval.extend( reference() );
+
+ if ( interval.width() == 0.0 )
+ interval = buildInterval( interval.minValue() );
+
+ stepSize = divideInterval( interval.width(), qMax( maxNumSteps, 1 ) );
+
+ if ( !testAttribute( QwtScaleEngine::Floating ) )
+ interval = align( interval, stepSize );
+
+ x1 = interval.minValue();
+ x2 = interval.maxValue();
+
+ if ( testAttribute( QwtScaleEngine::Inverted ) )
+ {
+ qSwap( x1, x2 );
+ stepSize = -stepSize;
+ }
+}
+
+/*!
+ \brief Calculate a scale division
+
+ \param x1 First interval limit
+ \param x2 Second interval limit
+ \param maxMajSteps Maximum for the number of major steps
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size. If stepSize == 0, the scaleEngine
+ calculates one.
+
+ \sa QwtScaleEngine::stepSize(), QwtScaleEngine::subDivide()
+*/
+QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2,
+ int maxMajSteps, int maxMinSteps, double stepSize ) const
+{
+ QwtInterval interval = QwtInterval( x1, x2 ).normalized();
+ if ( interval.width() <= 0 )
+ return QwtScaleDiv();
+
+ stepSize = qAbs( stepSize );
+ if ( stepSize == 0.0 )
+ {
+ if ( maxMajSteps < 1 )
+ maxMajSteps = 1;
+
+ stepSize = divideInterval( interval.width(), maxMajSteps );
+ }
+
+ QwtScaleDiv scaleDiv;
+
+ if ( stepSize != 0.0 )
+ {
+ QList<double> ticks[QwtScaleDiv::NTickTypes];
+ buildTicks( interval, stepSize, maxMinSteps, ticks );
+
+ scaleDiv = QwtScaleDiv( interval, ticks );
+ }
+
+ if ( x1 > x2 )
+ scaleDiv.invert();
+
+ return scaleDiv;
+}
+
+/*!
+ \brief Calculate ticks for an interval
+
+ \param interval Interval
+ \param stepSize Step size
+ \param maxMinSteps Maximum number of minor steps
+ \param ticks Arrays to be filled with the calculated ticks
+
+ \sa buildMajorTicks(), buildMinorTicks
+*/
+void QwtLinearScaleEngine::buildTicks(
+ const QwtInterval& interval, double stepSize, int maxMinSteps,
+ QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
+{
+ const QwtInterval boundingInterval = align( interval, stepSize );
+
+ ticks[QwtScaleDiv::MajorTick] =
+ buildMajorTicks( boundingInterval, stepSize );
+
+ if ( maxMinSteps > 0 )
+ {
+ buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
+ ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
+ }
+
+ for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
+ {
+ ticks[i] = strip( ticks[i], interval );
+
+ // ticks very close to 0.0 are
+ // explicitely set to 0.0
+
+ for ( int j = 0; j < ticks[i].count(); j++ )
+ {
+ if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 )
+ ticks[i][j] = 0.0;
+ }
+ }
+}
+
+/*!
+ \brief Calculate major ticks for an interval
+
+ \param interval Interval
+ \param stepSize Step size
+
+ \return Calculated ticks
+*/
+QList<double> QwtLinearScaleEngine::buildMajorTicks(
+ const QwtInterval &interval, double stepSize ) const
+{
+ int numTicks = qRound( interval.width() / stepSize ) + 1;
+ if ( numTicks > 10000 )
+ numTicks = 10000;
+
+ QList<double> ticks;
+
+ ticks += interval.minValue();
+ for ( int i = 1; i < numTicks - 1; i++ )
+ ticks += interval.minValue() + i * stepSize;
+ ticks += interval.maxValue();
+
+ return ticks;
+}
+
+/*!
+ \brief Calculate minor/medium ticks for major ticks
+
+ \param majorTicks Major ticks
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size
+ \param minorTicks Array to be filled with the calculated minor ticks
+ \param mediumTicks Array to be filled with the calculated medium ticks
+
+*/
+void QwtLinearScaleEngine::buildMinorTicks(
+ const QList<double>& majorTicks,
+ int maxMinSteps, double stepSize,
+ QList<double> &minorTicks,
+ QList<double> &mediumTicks ) const
+{
+ double minStep = divideInterval( stepSize, maxMinSteps );
+ if ( minStep == 0.0 )
+ return;
+
+ // # ticks per interval
+ int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
+
+ // Do the minor steps fit into the interval?
+ if ( qwtFuzzyCompare( ( numTicks + 1 ) * qAbs( minStep ),
+ qAbs( stepSize ), stepSize ) > 0 )
+ {
+ numTicks = 1;
+ minStep = stepSize * 0.5;
+ }
+
+ int medIndex = -1;
+ if ( numTicks % 2 )
+ medIndex = numTicks / 2;
+
+ // calculate minor ticks
+
+ for ( int i = 0; i < majorTicks.count(); i++ )
+ {
+ double val = majorTicks[i];
+ for ( int k = 0; k < numTicks; k++ )
+ {
+ val += minStep;
+
+ double alignedValue = val;
+ if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 )
+ alignedValue = 0.0;
+
+ if ( k == medIndex )
+ mediumTicks += alignedValue;
+ else
+ minorTicks += alignedValue;
+ }
+ }
+}
+
+/*!
+ \brief Align an interval to a step size
+
+ The limits of an interval are aligned that both are integer
+ multiples of the step size.
+
+ \param interval Interval
+ \param stepSize Step size
+
+ \return Aligned interval
+*/
+QwtInterval QwtLinearScaleEngine::align(
+ const QwtInterval &interval, double stepSize ) const
+{
+ double x1 = interval.minValue();
+ double x2 = interval.maxValue();
+
+ if ( -DBL_MAX + stepSize <= x1 )
+ {
+ const double x = QwtScaleArithmetic::floorEps( x1, stepSize );
+ if ( qwtFuzzyCompare( x1, x, stepSize ) != 0 )
+ x1 = x;
+ }
+
+ if ( DBL_MAX - stepSize >= x2 )
+ {
+ const double x = QwtScaleArithmetic::ceilEps( x2, stepSize );
+ if ( qwtFuzzyCompare( x2, x, stepSize ) != 0 )
+ x2 = x;
+ }
+
+ return QwtInterval( x1, x2 );
+}
+
+/*!
+ Return a transformation, for logarithmic (base 10) scales
+*/
+QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const
+{
+ return new QwtScaleTransformation( QwtScaleTransformation::Log10 );
+}
+
+/*!
+ Align and divide an interval
+
+ \param maxNumSteps Max. number of steps
+ \param x1 First limit of the interval (In/Out)
+ \param x2 Second limit of the interval (In/Out)
+ \param stepSize Step size (Out)
+
+ \sa QwtScaleEngine::setAttribute()
+*/
+void QwtLog10ScaleEngine::autoScale( int maxNumSteps,
+ double &x1, double &x2, double &stepSize ) const
+{
+ if ( x1 > x2 )
+ qSwap( x1, x2 );
+
+ QwtInterval interval( x1 / qPow( 10.0, lowerMargin() ),
+ x2 * qPow( 10.0, upperMargin() ) );
+
+ if ( interval.maxValue() / interval.minValue() < 10.0 )
+ {
+ // scale width is less than one decade -> build linear scale
+
+ QwtLinearScaleEngine linearScaler;
+ linearScaler.setAttributes( attributes() );
+ linearScaler.setReference( reference() );
+ linearScaler.setMargins( lowerMargin(), upperMargin() );
+
+ linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
+
+ if ( stepSize < 0.0 )
+ stepSize = -::log10( qAbs( stepSize ) );
+ else
+ stepSize = ::log10( stepSize );
+
+ return;
+ }
+
+ double logRef = 1.0;
+ if ( reference() > LOG_MIN / 2 )
+ logRef = qMin( reference(), LOG_MAX / 2 );
+
+ if ( testAttribute( QwtScaleEngine::Symmetric ) )
+ {
+ const double delta = qMax( interval.maxValue() / logRef,
+ logRef / interval.minValue() );
+ interval.setInterval( logRef / delta, logRef * delta );
+ }
+
+ if ( testAttribute( QwtScaleEngine::IncludeReference ) )
+ interval = interval.extend( logRef );
+
+ interval = interval.limited( LOG_MIN, LOG_MAX );
+
+ if ( interval.width() == 0.0 )
+ interval = buildInterval( interval.minValue() );
+
+ stepSize = divideInterval( log10( interval ).width(), qMax( maxNumSteps, 1 ) );
+ if ( stepSize < 1.0 )
+ stepSize = 1.0;
+
+ if ( !testAttribute( QwtScaleEngine::Floating ) )
+ interval = align( interval, stepSize );
+
+ x1 = interval.minValue();
+ x2 = interval.maxValue();
+
+ if ( testAttribute( QwtScaleEngine::Inverted ) )
+ {
+ qSwap( x1, x2 );
+ stepSize = -stepSize;
+ }
+}
+
+/*!
+ \brief Calculate a scale division
+
+ \param x1 First interval limit
+ \param x2 Second interval limit
+ \param maxMajSteps Maximum for the number of major steps
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size. If stepSize == 0, the scaleEngine
+ calculates one.
+
+ \sa QwtScaleEngine::stepSize(), QwtLog10ScaleEngine::subDivide()
+*/
+QwtScaleDiv QwtLog10ScaleEngine::divideScale( double x1, double x2,
+ int maxMajSteps, int maxMinSteps, double stepSize ) const
+{
+ QwtInterval interval = QwtInterval( x1, x2 ).normalized();
+ interval = interval.limited( LOG_MIN, LOG_MAX );
+
+ if ( interval.width() <= 0 )
+ return QwtScaleDiv();
+
+ if ( interval.maxValue() / interval.minValue() < 10.0 )
+ {
+ // scale width is less than one decade -> build linear scale
+
+ QwtLinearScaleEngine linearScaler;
+ linearScaler.setAttributes( attributes() );
+ linearScaler.setReference( reference() );
+ linearScaler.setMargins( lowerMargin(), upperMargin() );
+
+ if ( stepSize != 0.0 )
+ {
+ if ( stepSize < 0.0 )
+ stepSize = -qPow( 10.0, -stepSize );
+ else
+ stepSize = qPow( 10.0, stepSize );
+ }
+
+ return linearScaler.divideScale( x1, x2,
+ maxMajSteps, maxMinSteps, stepSize );
+ }
+
+ stepSize = qAbs( stepSize );
+ if ( stepSize == 0.0 )
+ {
+ if ( maxMajSteps < 1 )
+ maxMajSteps = 1;
+
+ stepSize = divideInterval( log10( interval ).width(), maxMajSteps );
+ if ( stepSize < 1.0 )
+ stepSize = 1.0; // major step must be >= 1 decade
+ }
+
+ QwtScaleDiv scaleDiv;
+ if ( stepSize != 0.0 )
+ {
+ QList<double> ticks[QwtScaleDiv::NTickTypes];
+ buildTicks( interval, stepSize, maxMinSteps, ticks );
+
+ scaleDiv = QwtScaleDiv( interval, ticks );
+ }
+
+ if ( x1 > x2 )
+ scaleDiv.invert();
+
+ return scaleDiv;
+}
+
+/*!
+ \brief Calculate ticks for an interval
+
+ \param interval Interval
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size
+ \param ticks Arrays to be filled with the calculated ticks
+
+ \sa buildMajorTicks(), buildMinorTicks
+*/
+void QwtLog10ScaleEngine::buildTicks(
+ const QwtInterval& interval, double stepSize, int maxMinSteps,
+ QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
+{
+ const QwtInterval boundingInterval = align( interval, stepSize );
+
+ ticks[QwtScaleDiv::MajorTick] =
+ buildMajorTicks( boundingInterval, stepSize );
+
+ if ( maxMinSteps > 0 )
+ {
+ ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
+ ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize );
+ }
+
+ for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
+ ticks[i] = strip( ticks[i], interval );
+}
+
+/*!
+ \brief Calculate major ticks for an interval
+
+ \param interval Interval
+ \param stepSize Step size
+
+ \return Calculated ticks
+*/
+QList<double> QwtLog10ScaleEngine::buildMajorTicks(
+ const QwtInterval &interval, double stepSize ) const
+{
+ double width = log10( interval ).width();
+
+ int numTicks = qRound( width / stepSize ) + 1;
+ if ( numTicks > 10000 )
+ numTicks = 10000;
+
+ const double lxmin = ::log( interval.minValue() );
+ const double lxmax = ::log( interval.maxValue() );
+ const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 );
+
+ QList<double> ticks;
+
+ ticks += interval.minValue();
+
+ for ( int i = 1; i < numTicks - 1; i++ )
+ ticks += qExp( lxmin + double( i ) * lstep );
+
+ ticks += interval.maxValue();
+
+ return ticks;
+}
+
+/*!
+ \brief Calculate minor/medium ticks for major ticks
+
+ \param majorTicks Major ticks
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size
+*/
+QList<double> QwtLog10ScaleEngine::buildMinorTicks(
+ const QList<double> &majorTicks,
+ int maxMinSteps, double stepSize ) const
+{
+ if ( stepSize < 1.1 ) // major step width is one decade
+ {
+ if ( maxMinSteps < 1 )
+ return QList<double>();
+
+ int k0, kstep, kmax;
+
+ if ( maxMinSteps >= 8 )
+ {
+ k0 = 2;
+ kmax = 9;
+ kstep = 1;
+ }
+ else if ( maxMinSteps >= 4 )
+ {
+ k0 = 2;
+ kmax = 8;
+ kstep = 2;
+ }
+ else if ( maxMinSteps >= 2 )
+ {
+ k0 = 2;
+ kmax = 5;
+ kstep = 3;
+ }
+ else
+ {
+ k0 = 5;
+ kmax = 5;
+ kstep = 1;
+ }
+
+ QList<double> minorTicks;
+
+ for ( int i = 0; i < majorTicks.count(); i++ )
+ {
+ const double v = majorTicks[i];
+ for ( int k = k0; k <= kmax; k += kstep )
+ minorTicks += v * double( k );
+ }
+
+ return minorTicks;
+ }
+ else // major step > one decade
+ {
+ double minStep = divideInterval( stepSize, maxMinSteps );
+ if ( minStep == 0.0 )
+ return QList<double>();
+
+ if ( minStep < 1.0 )
+ minStep = 1.0;
+
+ // # subticks per interval
+ int nMin = qRound( stepSize / minStep ) - 1;
+
+ // Do the minor steps fit into the interval?
+
+ if ( qwtFuzzyCompare( ( nMin + 1 ) * minStep,
+ qAbs( stepSize ), stepSize ) > 0 )
+ {
+ nMin = 0;
+ }
+
+ if ( nMin < 1 )
+ return QList<double>(); // no subticks
+
+ // substep factor = 10^substeps
+ const qreal minFactor = qMax( qPow( 10.0, minStep ), qreal( 10.0 ) );
+
+ QList<double> minorTicks;
+ for ( int i = 0; i < majorTicks.count(); i++ )
+ {
+ double val = majorTicks[i];
+ for ( int k = 0; k < nMin; k++ )
+ {
+ val *= minFactor;
+ minorTicks += val;
+ }
+ }
+ return minorTicks;
+ }
+}
+
+/*!
+ \brief Align an interval to a step size
+
+ The limits of an interval are aligned that both are integer
+ multiples of the step size.
+
+ \param interval Interval
+ \param stepSize Step size
+
+ \return Aligned interval
+*/
+QwtInterval QwtLog10ScaleEngine::align(
+ const QwtInterval &interval, double stepSize ) const
+{
+ const QwtInterval intv = log10( interval );
+
+ double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
+ if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
+ x1 = interval.minValue();
+
+ double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize );
+ if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
+ x2 = interval.maxValue();
+
+ return pow10( QwtInterval( x1, x2 ) );
+}
+
+/*!
+ Return the interval [log10(interval.minValue(), log10(interval.maxValue]
+*/
+
+QwtInterval QwtLog10ScaleEngine::log10( const QwtInterval &interval ) const
+{
+ return QwtInterval( ::log10( interval.minValue() ),
+ ::log10( interval.maxValue() ) );
+}
+
+/*!
+ Return the interval [pow10(interval.minValue(), pow10(interval.maxValue]
+*/
+QwtInterval QwtLog10ScaleEngine::pow10( const QwtInterval &interval ) const
+{
+ return QwtInterval( qPow( 10.0, interval.minValue() ),
+ qPow( 10.0, interval.maxValue() ) );
+}
diff --git a/src/libpcp_qwt/src/qwt_scale_engine.h b/src/libpcp_qwt/src/qwt_scale_engine.h
new file mode 100644
index 0000000..a7b2c74
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_engine.h
@@ -0,0 +1,217 @@
+/* -*- 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_SCALE_ENGINE_H
+#define QWT_SCALE_ENGINE_H
+
+#include "qwt_global.h"
+#include "qwt_scale_div.h"
+#include "qwt_interval.h"
+
+class QwtScaleTransformation;
+
+/*!
+ \brief Arithmetic including a tolerance
+*/
+class QWT_EXPORT QwtScaleArithmetic
+{
+public:
+ static double ceilEps( double value, double intervalSize );
+ static double floorEps( double value, double intervalSize );
+
+ static double divideEps( double interval, double steps );
+
+ static double ceil125( double x );
+ static double floor125( double x );
+};
+
+/*!
+ \brief Base class for scale engines.
+
+ A scale engine tries to find "reasonable" ranges and step sizes
+ for scales.
+
+ The layout of the scale can be varied with setAttribute().
+
+ Qwt offers implementations for logarithmic (log10)
+ and linear scales. Contributions for other types of scale engines
+ (date/time, log2 ... ) are welcome.
+*/
+
+class QWT_EXPORT QwtScaleEngine
+{
+public:
+ /*!
+ Layout attributes
+ \sa setAttribute(), testAttribute(), reference(),
+ lowerMargin(), upperMargin()
+ */
+
+ enum Attribute
+ {
+ //! No attributes
+ NoAttribute = 0x00,
+
+ //! Build a scale which includes the reference() value.
+ IncludeReference = 0x01,
+
+ //! Build a scale which is symmetric to the reference() value.
+ Symmetric = 0x02,
+
+ /*!
+ The endpoints of the scale are supposed to be equal the
+ outmost included values plus the specified margins
+ (see setMargins()).
+ If this attribute is *not* set, the endpoints of the scale will
+ be integer multiples of the step size.
+ */
+ Floating = 0x04,
+
+ //! Turn the scale upside down.
+ Inverted = 0x08
+ };
+
+ //! Layout attributes
+ typedef QFlags<Attribute> Attributes;
+
+ explicit QwtScaleEngine();
+ virtual ~QwtScaleEngine();
+
+ void setAttribute( Attribute, bool on = true );
+ bool testAttribute( Attribute ) const;
+
+ void setAttributes( Attributes );
+ Attributes attributes() const;
+
+ void setReference( double reference );
+ double reference() const;
+
+ void setMargins( double lower, double upper );
+ double lowerMargin() const;
+ double upperMargin() const;
+
+ /*!
+ Align and divide an interval
+
+ \param maxNumSteps Max. number of steps
+ \param x1 First limit of the interval (In/Out)
+ \param x2 Second limit of the interval (In/Out)
+ \param stepSize Step size (Return value)
+ */
+ virtual void autoScale( int maxNumSteps,
+ double &x1, double &x2, double &stepSize ) const = 0;
+
+ /*!
+ \brief Calculate a scale division
+
+ \param x1 First interval limit
+ \param x2 Second interval limit
+ \param maxMajSteps Maximum for the number of major steps
+ \param maxMinSteps Maximum number of minor steps
+ \param stepSize Step size. If stepSize == 0.0, the scaleEngine
+ calculates one.
+ */
+ virtual QwtScaleDiv divideScale( double x1, double x2,
+ int maxMajSteps, int maxMinSteps,
+ double stepSize = 0.0 ) const = 0;
+
+ //! \return a transformation
+ virtual QwtScaleTransformation *transformation() const = 0;
+
+protected:
+ bool contains( const QwtInterval &, double val ) const;
+ QList<double> strip( const QList<double>&, const QwtInterval & ) const;
+ double divideInterval( double interval, int numSteps ) const;
+
+ QwtInterval buildInterval( double v ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+/*!
+ \brief A scale engine for linear scales
+
+ The step size will fit into the pattern
+ \f$\left\{ 1,2,5\right\} \cdot 10^{n}\f$, where n is an integer.
+*/
+
+class QWT_EXPORT QwtLinearScaleEngine: public QwtScaleEngine
+{
+public:
+ virtual void autoScale( int maxSteps,
+ double &x1, double &x2, double &stepSize ) const;
+
+ virtual QwtScaleDiv divideScale( double x1, double x2,
+ int numMajorSteps, int numMinorSteps,
+ double stepSize = 0.0 ) const;
+
+ virtual QwtScaleTransformation *transformation() const;
+
+protected:
+ QwtInterval align( const QwtInterval&, double stepSize ) const;
+
+ void buildTicks(
+ const QwtInterval &, double stepSize, int maxMinSteps,
+ QList<double> ticks[QwtScaleDiv::NTickTypes] ) const;
+
+ QList<double> buildMajorTicks(
+ const QwtInterval &interval, double stepSize ) const;
+
+ void buildMinorTicks(
+ const QList<double>& majorTicks,
+ int maxMinMark, double step,
+ QList<double> &, QList<double> & ) const;
+};
+
+/*!
+ \brief A scale engine for logarithmic (base 10) scales
+
+ The step size is measured in *decades*
+ and the major step size will be adjusted to fit the pattern
+ \f$\left\{ 1,2,3,5\right\} \cdot 10^{n}\f$, where n is a natural number
+ including zero.
+
+ \warning the step size as well as the margins are measured in *decades*.
+*/
+
+class QWT_EXPORT QwtLog10ScaleEngine: public QwtScaleEngine
+{
+public:
+ virtual void autoScale( int maxSteps,
+ double &x1, double &x2, double &stepSize ) const;
+
+ virtual QwtScaleDiv divideScale( double x1, double x2,
+ int numMajorSteps, int numMinorSteps,
+ double stepSize = 0.0 ) const;
+
+ virtual QwtScaleTransformation *transformation() const;
+
+protected:
+ QwtInterval log10( const QwtInterval& ) const;
+ QwtInterval pow10( const QwtInterval& ) const;
+
+ QwtInterval align( const QwtInterval&, double stepSize ) const;
+
+ void buildTicks(
+ const QwtInterval &, double stepSize, int maxMinSteps,
+ QList<double> ticks[QwtScaleDiv::NTickTypes] ) const;
+
+ QList<double> buildMajorTicks(
+ const QwtInterval &interval, double stepSize ) const;
+
+ QList<double> buildMinorTicks(
+ const QList<double>& majorTicks,
+ int maxMinMark, double step ) const;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtScaleEngine::Attributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_map.cpp b/src/libpcp_qwt/src/qwt_scale_map.cpp
new file mode 100644
index 0000000..1e16be1
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_map.cpp
@@ -0,0 +1,344 @@
+/* -*- 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_scale_map.h"
+#include <qrect.h>
+#include <qalgorithms.h>
+#include <qmath.h>
+#include <qdebug.h>
+
+#if QT_VERSION < 0x040601
+#define qExp(x) ::exp(x)
+#endif
+
+//! Smallest allowed value for logarithmic scales: 1.0e-150
+QT_STATIC_CONST_IMPL double QwtScaleMap::LogMin = 1.0e-150;
+
+//! Largest allowed value for logarithmic scales: 1.0e150
+QT_STATIC_CONST_IMPL double QwtScaleMap::LogMax = 1.0e150;
+
+//! Constructor for a linear transformation
+QwtScaleTransformation::QwtScaleTransformation( Type type ):
+ d_type( type )
+{
+}
+
+//! Destructor
+QwtScaleTransformation::~QwtScaleTransformation()
+{
+}
+
+//! Create a clone of the transformation
+QwtScaleTransformation *QwtScaleTransformation::copy() const
+{
+ return new QwtScaleTransformation( d_type );
+}
+
+/*!
+ \brief Transform a value from the coordinate system of a scale
+ into the coordinate system of the paint device
+
+ \param s Value related to the coordinate system of the scale
+ \param s1 First border of the coordinate system of the scale
+ \param s2 Second border of the coordinate system of the scale
+ \param p1 First border of the coordinate system of the paint device
+ \param p2 Second border of the coordinate system of the paint device
+ \return
+ <dl>
+ <dt>linear mapping:<dd>p1 + (p2 - p1) / (s2 - s1) * (s - s1);</dd>
+ </dl>
+ <dl>
+ <dt>log10 mapping: <dd>p1 + (p2 - p1) / log(s2 / s1) * log(s / s1);</dd>
+ </dl>
+*/
+
+double QwtScaleTransformation::xForm(
+ double s, double s1, double s2, double p1, double p2 ) const
+{
+ if ( d_type == Log10 )
+ return p1 + ( p2 - p1 ) / log( s2 / s1 ) * log( s / s1 );
+ else
+ return p1 + ( p2 - p1 ) / ( s2 - s1 ) * ( s - s1 );
+}
+
+/*!
+ \brief Transform a value from the coordinate system of the paint device
+ into the coordinate system of a scale.
+
+ \param p Value related to the coordinate system of the paint device
+ \param p1 First border of the coordinate system of the paint device
+ \param p2 Second border of the coordinate system of the paint device
+ \param s1 First border of the coordinate system of the scale
+ \param s2 Second border of the coordinate system of the scale
+ \return
+ <dl>
+ <dt>linear mapping:<dd>s1 + ( s2 - s1 ) / ( p2 - p1 ) * ( p - p1 );</dd>
+ </dl>
+ <dl>
+ <dt>log10 mapping:<dd>exp((p - p1) / (p2 - p1) * log(s2 / s1)) * s1;</dd>
+ </dl>
+*/
+
+double QwtScaleTransformation::invXForm( double p, double p1, double p2,
+ double s1, double s2 ) const
+{
+ if ( d_type == Log10 )
+ return qExp( ( p - p1 ) / ( p2 - p1 ) * log( s2 / s1 ) ) * s1;
+ else
+ return s1 + ( s2 - s1 ) / ( p2 - p1 ) * ( p - p1 );
+}
+
+/*!
+ \brief Constructor
+
+ The scale and paint device intervals are both set to [0,1].
+*/
+QwtScaleMap::QwtScaleMap():
+ d_s1( 0.0 ),
+ d_s2( 1.0 ),
+ d_p1( 0.0 ),
+ d_p2( 1.0 ),
+ d_cnv( 1.0 )
+{
+ d_transformation = new QwtScaleTransformation(
+ QwtScaleTransformation::Linear );
+}
+
+//! Copy constructor
+QwtScaleMap::QwtScaleMap( const QwtScaleMap& other ):
+ d_s1( other.d_s1 ),
+ d_s2( other.d_s2 ),
+ d_p1( other.d_p1 ),
+ d_p2( other.d_p2 ),
+ d_cnv( other.d_cnv )
+{
+ d_transformation = other.d_transformation->copy();
+}
+
+/*!
+ Destructor
+*/
+QwtScaleMap::~QwtScaleMap()
+{
+ delete d_transformation;
+}
+
+//! Assignment operator
+QwtScaleMap &QwtScaleMap::operator=( const QwtScaleMap & other )
+{
+ d_s1 = other.d_s1;
+ d_s2 = other.d_s2;
+ d_p1 = other.d_p1;
+ d_p2 = other.d_p2;
+ d_cnv = other.d_cnv;
+
+ delete d_transformation;
+ d_transformation = other.d_transformation->copy();
+
+ return *this;
+}
+
+/*!
+ Initialize the map with a transformation
+*/
+void QwtScaleMap::setTransformation(
+ QwtScaleTransformation *transformation )
+{
+ if ( transformation == NULL )
+ return;
+
+ if ( transformation != d_transformation )
+ {
+ delete d_transformation;
+ d_transformation = transformation;
+ }
+
+ setScaleInterval( d_s1, d_s2 );
+}
+
+//! Get the transformation
+const QwtScaleTransformation *QwtScaleMap::transformation() const
+{
+ return d_transformation;
+}
+
+/*!
+ \brief Specify the borders of the scale interval
+ \param s1 first border
+ \param s2 second border
+ \warning logarithmic scales might be aligned to [LogMin, LogMax]
+*/
+void QwtScaleMap::setScaleInterval( double s1, double s2 )
+{
+ if ( d_transformation->type() == QwtScaleTransformation::Log10 )
+ {
+ if ( s1 < LogMin )
+ s1 = LogMin;
+ else if ( s1 > LogMax )
+ s1 = LogMax;
+
+ if ( s2 < LogMin )
+ s2 = LogMin;
+ else if ( s2 > LogMax )
+ s2 = LogMax;
+ }
+
+ d_s1 = s1;
+ d_s2 = s2;
+
+ if ( d_transformation->type() != QwtScaleTransformation::Other )
+ newFactor();
+}
+
+/*!
+ \brief Specify the borders of the paint device interval
+ \param p1 first border
+ \param p2 second border
+*/
+void QwtScaleMap::setPaintInterval( double p1, double p2 )
+{
+ d_p1 = p1;
+ d_p2 = p2;
+
+ if ( d_transformation->type() != QwtScaleTransformation::Other )
+ newFactor();
+}
+
+/*!
+ \brief Re-calculate the conversion factor.
+*/
+void QwtScaleMap::newFactor()
+{
+ d_cnv = 0.0;
+
+ switch ( d_transformation->type() )
+ {
+ case QwtScaleTransformation::Linear:
+ {
+ if ( d_s2 != d_s1 )
+ d_cnv = ( d_p2 - d_p1 ) / ( d_s2 - d_s1 );
+ break;
+ }
+ case QwtScaleTransformation::Log10:
+ {
+ if ( d_s1 != 0 )
+ d_cnv = ( d_p2 - d_p1 ) / log( d_s2 / d_s1 );
+ break;
+ }
+ default:;
+ }
+}
+
+/*!
+ Transform a rectangle from scale to paint coordinates
+
+ \param xMap X map
+ \param yMap Y map
+ \param rect Rectangle in scale coordinates
+ \return Rectangle in paint coordinates
+
+ \sa invTransform()
+*/
+QRectF QwtScaleMap::transform( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap, const QRectF &rect )
+{
+ double x1 = xMap.transform( rect.left() );
+ double x2 = xMap.transform( rect.right() );
+ double y1 = yMap.transform( rect.top() );
+ double y2 = yMap.transform( rect.bottom() );
+
+ if ( x2 < x1 )
+ qSwap( x1, x2 );
+ if ( y2 < y1 )
+ qSwap( y1, y2 );
+
+ if ( qwtFuzzyCompare( x1, 0.0, x2 - x1 ) == 0 )
+ x1 = 0.0;
+ if ( qwtFuzzyCompare( x2, 0.0, x2 - x1 ) == 0 )
+ x2 = 0.0;
+ if ( qwtFuzzyCompare( y1, 0.0, y2 - y1 ) == 0 )
+ y1 = 0.0;
+ if ( qwtFuzzyCompare( y2, 0.0, y2 - y1 ) == 0 )
+ y2 = 0.0;
+
+ return QRectF( x1, y1, x2 - x1 + 1, y2 - y1 + 1 );
+}
+
+/*!
+ Transform a rectangle from paint to scale coordinates
+
+ \param xMap X map
+ \param yMap Y map
+ \param pos Position in paint coordinates
+ \return Position in scale coordinates
+ \sa transform()
+*/
+QPointF QwtScaleMap::invTransform( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap, const QPointF &pos )
+{
+ return QPointF(
+ xMap.invTransform( pos.x() ),
+ yMap.invTransform( pos.y() )
+ );
+}
+
+/*!
+ Transform a point from scale to paint coordinates
+
+ \param xMap X map
+ \param yMap Y map
+ \param pos Position in scale coordinates
+ \return Position in paint coordinates
+
+ \sa invTransform()
+*/
+QPointF QwtScaleMap::transform( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap, const QPointF &pos )
+{
+ return QPointF(
+ xMap.transform( pos.x() ),
+ yMap.transform( pos.y() )
+ );
+}
+
+/*!
+ Transform a rectangle from paint to scale coordinates
+
+ \param xMap X map
+ \param yMap Y map
+ \param rect Rectangle in paint coordinates
+ \return Rectangle in scale coordinates
+ \sa transform()
+*/
+QRectF QwtScaleMap::invTransform( const QwtScaleMap &xMap,
+ const QwtScaleMap &yMap, const QRectF &rect )
+{
+ const double x1 = xMap.invTransform( rect.left() );
+ const double x2 = xMap.invTransform( rect.right() - 1 );
+ const double y1 = yMap.invTransform( rect.top() );
+ const double y2 = yMap.invTransform( rect.bottom() - 1 );
+
+ const QRectF r( x1, y1, x2 - x1, y2 - y1 );
+ return r.normalized();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<( QDebug debug, const QwtScaleMap &map )
+{
+ debug.nospace() << "QwtScaleMap("
+ << static_cast<int>( map.transformation()->type() )
+ << ", s:" << map.s1() << "->" << map.s2()
+ << ", p:" << map.p1() << "->" << map.p2()
+ << ")";
+
+ return debug.space();
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_map.h b/src/libpcp_qwt/src/qwt_scale_map.h
new file mode 100644
index 0000000..31dbb67
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_map.h
@@ -0,0 +1,219 @@
+/* -*- 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_SCALE_MAP_H
+#define QWT_SCALE_MAP_H
+
+#include "qwt_global.h"
+#include "qwt_math.h"
+#ifndef QT_NO_DEBUG_STREAM
+#include <qdebug.h>
+#endif
+
+class QRectF;
+
+/*!
+ \brief A transformation between coordinate systems
+
+ QwtScaleTransformation offers transformations from the coordinate system
+ of a scale into the linear coordinate system of a paint device
+ and vice versa.
+*/
+class QWT_EXPORT QwtScaleTransformation
+{
+public:
+ //! Transformation type
+ enum Type
+ {
+ //! Transformation between 2 linear scales
+ Linear,
+
+ //! Transformation between a linear and a logarithmic ( base 10 ) scale
+ Log10,
+
+ //! Any other type of transformation
+ Other
+ };
+
+ QwtScaleTransformation( Type type );
+ virtual ~QwtScaleTransformation();
+
+ virtual double xForm( double s, double s1, double s2,
+ double p1, double p2 ) const;
+ virtual double invXForm( double p, double p1, double p2,
+ double s1, double s2 ) const;
+
+ Type type() const;
+
+ virtual QwtScaleTransformation *copy() const;
+
+private:
+ QwtScaleTransformation();
+ QwtScaleTransformation &operator=( const QwtScaleTransformation );
+
+ const Type d_type;
+};
+
+//! \return Transformation type
+inline QwtScaleTransformation::Type QwtScaleTransformation::type() const
+{
+ return d_type;
+}
+
+/*!
+ \brief A scale map
+
+ QwtScaleMap offers transformations from the coordinate system
+ of a scale into the linear coordinate system of a paint device
+ and vice versa.
+*/
+class QWT_EXPORT QwtScaleMap
+{
+public:
+ QwtScaleMap();
+ QwtScaleMap( const QwtScaleMap& );
+
+ ~QwtScaleMap();
+
+ QwtScaleMap &operator=( const QwtScaleMap & );
+
+ void setTransformation( QwtScaleTransformation * );
+ const QwtScaleTransformation *transformation() const;
+
+ void setPaintInterval( double p1, double p2 );
+ void setScaleInterval( double s1, double s2 );
+
+ double transform( double s ) const;
+ double invTransform( double p ) const;
+
+ double p1() const;
+ double p2() const;
+
+ double s1() const;
+ double s2() const;
+
+ double pDist() const;
+ double sDist() const;
+
+ QT_STATIC_CONST double LogMin;
+ QT_STATIC_CONST double LogMax;
+
+ static QRectF transform( const QwtScaleMap &,
+ const QwtScaleMap &, const QRectF & );
+ static QRectF invTransform( const QwtScaleMap &,
+ const QwtScaleMap &, const QRectF & );
+
+ static QPointF transform( const QwtScaleMap &,
+ const QwtScaleMap &, const QPointF & );
+ static QPointF invTransform( const QwtScaleMap &,
+ const QwtScaleMap &, const QPointF & );
+
+ bool isInverting() const;
+
+private:
+ void newFactor();
+
+ double d_s1, d_s2; // scale interval boundaries
+ double d_p1, d_p2; // paint device interval boundaries
+
+ double d_cnv; // conversion factor
+
+ QwtScaleTransformation *d_transformation;
+};
+
+/*!
+ \return First border of the scale interval
+*/
+inline double QwtScaleMap::s1() const
+{
+ return d_s1;
+}
+
+/*!
+ \return Second border of the scale interval
+*/
+inline double QwtScaleMap::s2() const
+{
+ return d_s2;
+}
+
+/*!
+ \return First border of the paint interval
+*/
+inline double QwtScaleMap::p1() const
+{
+ return d_p1;
+}
+
+/*!
+ \return Second border of the paint interval
+*/
+inline double QwtScaleMap::p2() const
+{
+ return d_p2;
+}
+
+/*!
+ \return qwtAbs(p2() - p1())
+*/
+inline double QwtScaleMap::pDist() const
+{
+ return qAbs( d_p2 - d_p1 );
+}
+
+/*!
+ \return qwtAbs(s2() - s1())
+*/
+inline double QwtScaleMap::sDist() const
+{
+ return qAbs( d_s2 - d_s1 );
+}
+
+/*!
+ Transform a point related to the scale interval into an point
+ related to the interval of the paint device
+
+ \param s Value relative to the coordinates of the scale
+*/
+inline double QwtScaleMap::transform( double s ) const
+{
+ // try to inline code from QwtScaleTransformation
+
+ if ( d_transformation->type() == QwtScaleTransformation::Linear )
+ return d_p1 + ( s - d_s1 ) * d_cnv;
+
+ if ( d_transformation->type() == QwtScaleTransformation::Log10 )
+ return d_p1 + log( s / d_s1 ) * d_cnv;
+
+ return d_transformation->xForm( s, d_s1, d_s2, d_p1, d_p2 );
+}
+
+/*!
+ Transform an paint device value into a value in the
+ interval of the scale.
+
+ \param p Value relative to the coordinates of the paint device
+ \sa transform()
+*/
+inline double QwtScaleMap::invTransform( double p ) const
+{
+ return d_transformation->invXForm( p, d_p1, d_p2, d_s1, d_s2 );
+}
+
+//! \return True, when ( p1() < p2() ) != ( s1() < s2() )
+inline bool QwtScaleMap::isInverting() const
+{
+ return ( ( d_p1 < d_p2 ) != ( d_s1 < d_s2 ) );
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QWT_EXPORT QDebug operator<<( QDebug, const QwtScaleMap & );
+#endif
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_scale_widget.cpp b/src/libpcp_qwt/src/qwt_scale_widget.cpp
new file mode 100644
index 0000000..d9ffacc
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_widget.cpp
@@ -0,0 +1,918 @@
+/* -*- 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_scale_widget.h"
+#include "qwt_painter.h"
+#include "qwt_color_map.h"
+#include "qwt_scale_map.h"
+#include "qwt_math.h"
+#include "qwt_scale_div.h"
+#include "qwt_text.h"
+#include <qpainter.h>
+#include <qevent.h>
+#include <qmath.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+
+class QwtScaleWidget::PrivateData
+{
+public:
+ PrivateData():
+ scaleDraw( NULL )
+ {
+ colorBar.colorMap = NULL;
+ }
+
+ ~PrivateData()
+ {
+ delete scaleDraw;
+ delete colorBar.colorMap;
+ }
+
+ QwtScaleDraw *scaleDraw;
+
+ int borderDist[2];
+ int minBorderDist[2];
+ int scaleLength;
+ int margin;
+
+ int titleOffset;
+ int spacing;
+ QwtText title;
+
+ QwtScaleWidget::LayoutFlags layoutFlags;
+
+ struct t_colorBar
+ {
+ bool isEnabled;
+ int width;
+ QwtInterval interval;
+ QwtColorMap *colorMap;
+ } colorBar;
+};
+
+/*!
+ \brief Create a scale with the position QwtScaleWidget::Left
+ \param parent Parent widget
+*/
+QwtScaleWidget::QwtScaleWidget( QWidget *parent ):
+ QWidget( parent )
+{
+ initScale( QwtScaleDraw::LeftScale );
+}
+
+/*!
+ \brief Constructor
+ \param align Alignment.
+ \param parent Parent widget
+*/
+QwtScaleWidget::QwtScaleWidget(
+ QwtScaleDraw::Alignment align, QWidget *parent ):
+ QWidget( parent )
+{
+ initScale( align );
+}
+
+//! Destructor
+QwtScaleWidget::~QwtScaleWidget()
+{
+ delete d_data;
+}
+
+//! Initialize the scale
+void QwtScaleWidget::initScale( QwtScaleDraw::Alignment align )
+{
+ d_data = new PrivateData;
+
+ d_data->layoutFlags = 0;
+ if ( align == QwtScaleDraw::RightScale )
+ d_data->layoutFlags |= TitleInverted;
+
+ d_data->borderDist[0] = 0;
+ d_data->borderDist[1] = 0;
+ d_data->minBorderDist[0] = 0;
+ d_data->minBorderDist[1] = 0;
+ d_data->margin = 4;
+ d_data->titleOffset = 0;
+ d_data->spacing = 2;
+
+ d_data->scaleDraw = new QwtScaleDraw;
+ d_data->scaleDraw->setAlignment( align );
+ d_data->scaleDraw->setLength( 10 );
+
+ d_data->colorBar.colorMap = new QwtLinearColorMap();
+ d_data->colorBar.isEnabled = false;
+ d_data->colorBar.width = 10;
+
+ const int flags = Qt::AlignHCenter
+ | Qt::TextExpandTabs | Qt::TextWordWrap;
+ d_data->title.setRenderFlags( flags );
+ d_data->title.setFont( font() );
+
+ QSizePolicy policy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::Fixed );
+ if ( d_data->scaleDraw->orientation() == Qt::Vertical )
+ policy.transpose();
+
+ setSizePolicy( policy );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+}
+
+/*!
+ Toggle an layout flag
+
+ \param flag Layout flag
+ \param on true/false
+
+ \sa testLayoutFlag(), LayoutFlag
+*/
+void QwtScaleWidget::setLayoutFlag( LayoutFlag flag, bool on )
+{
+ if ( ( ( d_data->layoutFlags & flag ) != 0 ) != on )
+ {
+ if ( on )
+ d_data->layoutFlags |= flag;
+ else
+ d_data->layoutFlags &= ~flag;
+ }
+}
+
+/*!
+ Test a layout flag
+
+ \param flag Layout flag
+ \return true/false
+ \sa setLayoutFlag(), LayoutFlag
+*/
+bool QwtScaleWidget::testLayoutFlag( LayoutFlag flag ) const
+{
+ return ( d_data->layoutFlags & flag );
+}
+
+/*!
+ Give title new text contents
+
+ \param title New title
+ \sa title(), setTitle(const QwtText &);
+*/
+void QwtScaleWidget::setTitle( const QString &title )
+{
+ if ( d_data->title.text() != title )
+ {
+ d_data->title.setText( title );
+ layoutScale();
+ }
+}
+
+/*!
+ Give title new text contents
+
+ \param title New title
+ \sa title()
+ \warning The title flags are interpreted in
+ direction of the label, AlignTop, AlignBottom can't be set
+ as the title will always be aligned to the scale.
+*/
+void QwtScaleWidget::setTitle( const QwtText &title )
+{
+ QwtText t = title;
+ const int flags = title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom );
+ t.setRenderFlags( flags );
+
+ if ( t != d_data->title )
+ {
+ d_data->title = t;
+ layoutScale();
+ }
+}
+
+/*!
+ Change the alignment
+
+ \param alignment New alignment
+ \sa alignment()
+*/
+void QwtScaleWidget::setAlignment( QwtScaleDraw::Alignment alignment )
+{
+ if ( d_data->scaleDraw )
+ d_data->scaleDraw->setAlignment( alignment );
+
+ if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
+ {
+ QSizePolicy policy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::Fixed );
+ if ( d_data->scaleDraw->orientation() == Qt::Vertical )
+ policy.transpose();
+
+ setSizePolicy( policy );
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+ }
+
+ layoutScale();
+}
+
+
+/*!
+ \return position
+ \sa setPosition()
+*/
+QwtScaleDraw::Alignment QwtScaleWidget::alignment() const
+{
+ if ( !scaleDraw() )
+ return QwtScaleDraw::LeftScale;
+
+ return scaleDraw()->alignment();
+}
+
+/*!
+ Specify distances of the scale's endpoints from the
+ widget's borders. The actual borders will never be less
+ than minimum border distance.
+ \param dist1 Left or top Distance
+ \param dist2 Right or bottom distance
+ \sa borderDist()
+*/
+void QwtScaleWidget::setBorderDist( int dist1, int dist2 )
+{
+ if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] )
+ {
+ d_data->borderDist[0] = dist1;
+ d_data->borderDist[1] = dist2;
+ layoutScale();
+ }
+}
+
+/*!
+ \brief Specify the margin to the colorBar/base line.
+ \param margin Margin
+ \sa margin()
+*/
+void QwtScaleWidget::setMargin( int margin )
+{
+ margin = qMax( 0, margin );
+ if ( margin != d_data->margin )
+ {
+ d_data->margin = margin;
+ layoutScale();
+ }
+}
+
+/*!
+ \brief Specify the distance between color bar, scale and title
+ \param spacing Spacing
+ \sa spacing()
+*/
+void QwtScaleWidget::setSpacing( int spacing )
+{
+ spacing = qMax( 0, spacing );
+ if ( spacing != d_data->spacing )
+ {
+ d_data->spacing = spacing;
+ layoutScale();
+ }
+}
+
+/*!
+ \brief Change the alignment for the labels.
+
+ \sa QwtScaleDraw::setLabelAlignment(), setLabelRotation()
+*/
+void QwtScaleWidget::setLabelAlignment( Qt::Alignment alignment )
+{
+ d_data->scaleDraw->setLabelAlignment( alignment );
+ layoutScale();
+}
+
+/*!
+ \brief Change the rotation for the labels.
+ See QwtScaleDraw::setLabelRotation().
+
+ \param rotation Rotation
+ \sa QwtScaleDraw::setLabelRotation(), setLabelFlags()
+*/
+void QwtScaleWidget::setLabelRotation( double rotation )
+{
+ d_data->scaleDraw->setLabelRotation( rotation );
+ layoutScale();
+}
+
+/*!
+ Set a scale draw
+ sd has to be created with new and will be deleted in
+ ~QwtScaleWidget() or the next call of setScaleDraw().
+
+ \param sd ScaleDraw object
+ \sa scaleDraw()
+*/
+void QwtScaleWidget::setScaleDraw( QwtScaleDraw *sd )
+{
+ if ( sd == NULL || sd == d_data->scaleDraw )
+ return;
+
+ if ( d_data->scaleDraw )
+ sd->setAlignment( d_data->scaleDraw->alignment() );
+
+ delete d_data->scaleDraw;
+ d_data->scaleDraw = sd;
+
+ layoutScale();
+}
+
+/*!
+ scaleDraw of this scale
+ \sa setScaleDraw(), QwtScaleDraw::setScaleDraw()
+*/
+const QwtScaleDraw *QwtScaleWidget::scaleDraw() const
+{
+ return d_data->scaleDraw;
+}
+
+/*!
+ scaleDraw of this scale
+ \sa QwtScaleDraw::setScaleDraw()
+*/
+QwtScaleDraw *QwtScaleWidget::scaleDraw()
+{
+ return d_data->scaleDraw;
+}
+
+/*!
+ \return title
+ \sa setTitle()
+*/
+QwtText QwtScaleWidget::title() const
+{
+ return d_data->title;
+}
+
+/*!
+ \return start border distance
+ \sa setBorderDist()
+*/
+int QwtScaleWidget::startBorderDist() const
+{
+ return d_data->borderDist[0];
+}
+
+/*!
+ \return end border distance
+ \sa setBorderDist()
+*/
+int QwtScaleWidget::endBorderDist() const
+{
+ return d_data->borderDist[1];
+}
+
+/*!
+ \return margin
+ \sa setMargin()
+*/
+int QwtScaleWidget::margin() const
+{
+ return d_data->margin;
+}
+
+/*!
+ \return distance between scale and title
+ \sa setMargin()
+*/
+int QwtScaleWidget::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ \brief paintEvent
+*/
+void QwtScaleWidget::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+ painter.setClipRegion( event->region() );
+
+ QStyleOption opt;
+ opt.init(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
+
+ draw( &painter );
+}
+
+/*!
+ \brief draw the scale
+*/
+void QwtScaleWidget::draw( QPainter *painter ) const
+{
+ d_data->scaleDraw->draw( painter, palette() );
+
+ if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 &&
+ d_data->colorBar.interval.isValid() )
+ {
+ drawColorBar( painter, colorBarRect( contentsRect() ) );
+ }
+
+ QRect r = contentsRect();
+ if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
+ {
+ r.setLeft( r.left() + d_data->borderDist[0] );
+ r.setWidth( r.width() - d_data->borderDist[1] );
+ }
+ else
+ {
+ r.setTop( r.top() + d_data->borderDist[0] );
+ r.setHeight( r.height() - d_data->borderDist[1] );
+ }
+
+ if ( !d_data->title.isEmpty() )
+ drawTitle( painter, d_data->scaleDraw->alignment(), r );
+}
+
+/*!
+ Calculate the the rectangle for the color bar
+
+ \param rect Bounding rectangle for all components of the scale
+ \return Rectabgle for the color bar
+*/
+QRectF QwtScaleWidget::colorBarRect( const QRectF& rect ) const
+{
+ QRectF cr = rect;
+
+ if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
+ {
+ cr.setLeft( cr.left() + d_data->borderDist[0] );
+ cr.setWidth( cr.width() - d_data->borderDist[1] + 1 );
+ }
+ else
+ {
+ cr.setTop( cr.top() + d_data->borderDist[0] );
+ cr.setHeight( cr.height() - d_data->borderDist[1] + 1 );
+ }
+
+ switch ( d_data->scaleDraw->alignment() )
+ {
+ case QwtScaleDraw::LeftScale:
+ {
+ cr.setLeft( cr.right() - d_data->margin
+ - d_data->colorBar.width );
+ cr.setWidth( d_data->colorBar.width );
+ break;
+ }
+
+ case QwtScaleDraw::RightScale:
+ {
+ cr.setLeft( cr.left() + d_data->margin );
+ cr.setWidth( d_data->colorBar.width );
+ break;
+ }
+
+ case QwtScaleDraw::BottomScale:
+ {
+ cr.setTop( cr.top() + d_data->margin );
+ cr.setHeight( d_data->colorBar.width );
+ break;
+ }
+
+ case QwtScaleDraw::TopScale:
+ {
+ cr.setTop( cr.bottom() - d_data->margin
+ - d_data->colorBar.width );
+ cr.setHeight( d_data->colorBar.width );
+ break;
+ }
+ }
+
+ return cr;
+}
+
+/*!
+ Event handler for resize event
+ \param event Resize event
+*/
+void QwtScaleWidget::resizeEvent( QResizeEvent *event )
+{
+ Q_UNUSED( event );
+ layoutScale( false );
+}
+
+/*!
+ Recalculate the scale's geometry and layout based on
+ the current rect and fonts.
+
+ \param update_geometry Notify the layout system and call update
+ to redraw the scale
+*/
+
+void QwtScaleWidget::layoutScale( bool update_geometry )
+{
+ int bd0, bd1;
+ getBorderDistHint( bd0, bd1 );
+ if ( d_data->borderDist[0] > bd0 )
+ bd0 = d_data->borderDist[0];
+ if ( d_data->borderDist[1] > bd1 )
+ bd1 = d_data->borderDist[1];
+
+ int colorBarWidth = 0;
+ if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
+ colorBarWidth = d_data->colorBar.width + d_data->spacing;
+
+ const QRectF r = contentsRect();
+ double x, y, length;
+
+ if ( d_data->scaleDraw->orientation() == Qt::Vertical )
+ {
+ y = r.top() + bd0;
+ length = r.height() - ( bd0 + bd1 );
+
+ if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale )
+ x = r.right() - 1.0 - d_data->margin - colorBarWidth;
+ else
+ x = r.left() + d_data->margin + colorBarWidth;
+ }
+ else
+ {
+ x = r.left() + bd0;
+ length = r.width() - ( bd0 + bd1 );
+
+ if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale )
+ y = r.top() + d_data->margin + colorBarWidth;
+ else
+ y = r.bottom() - 1.0 - d_data->margin - colorBarWidth;
+ }
+
+ d_data->scaleDraw->move( x, y );
+ d_data->scaleDraw->setLength( length );
+
+ const int extent = qCeil( d_data->scaleDraw->extent( font() ) );
+
+ d_data->titleOffset =
+ d_data->margin + d_data->spacing + colorBarWidth + extent;
+
+ if ( update_geometry )
+ {
+ updateGeometry();
+ update();
+ }
+}
+
+/*!
+ Draw the color bar of the scale widget
+
+ \param painter Painter
+ \param rect Bounding rectangle for the color bar
+
+ \sa setColorBarEnabled()
+*/
+void QwtScaleWidget::drawColorBar( QPainter *painter, const QRectF& rect ) const
+{
+ if ( !d_data->colorBar.interval.isValid() )
+ return;
+
+ const QwtScaleDraw* sd = d_data->scaleDraw;
+
+ QwtPainter::drawColorBar( painter, *d_data->colorBar.colorMap,
+ d_data->colorBar.interval.normalized(), sd->scaleMap(),
+ sd->orientation(), rect );
+}
+
+/*!
+ Rotate and paint a title according to its position into a given rectangle.
+
+ \param painter Painter
+ \param align Alignment
+ \param rect Bounding rectangle
+*/
+
+void QwtScaleWidget::drawTitle( QPainter *painter,
+ QwtScaleDraw::Alignment align, const QRectF &rect ) const
+{
+ QRectF r = rect;
+ double angle;
+ int flags = d_data->title.renderFlags() &
+ ~( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter );
+
+ switch ( align )
+ {
+ case QwtScaleDraw::LeftScale:
+ angle = -90.0;
+ flags |= Qt::AlignTop;
+ r.setRect( r.left(), r.bottom(),
+ r.height(), r.width() - d_data->titleOffset );
+ break;
+
+ case QwtScaleDraw::RightScale:
+ angle = -90.0;
+ flags |= Qt::AlignTop;
+ r.setRect( r.left() + d_data->titleOffset, r.bottom(),
+ r.height(), r.width() - d_data->titleOffset );
+ break;
+
+ case QwtScaleDraw::BottomScale:
+ angle = 0.0;
+ flags |= Qt::AlignBottom;
+ r.setTop( r.top() + d_data->titleOffset );
+ break;
+
+ case QwtScaleDraw::TopScale:
+ default:
+ angle = 0.0;
+ flags |= Qt::AlignTop;
+ r.setBottom( r.bottom() - d_data->titleOffset );
+ break;
+ }
+
+ if ( d_data->layoutFlags & TitleInverted )
+ {
+ if ( align == QwtScaleDraw::LeftScale
+ || align == QwtScaleDraw::RightScale )
+ {
+ angle = -angle;
+ r.setRect( r.x() + r.height(), r.y() - r.width(),
+ r.width(), r.height() );
+ }
+ }
+
+ painter->save();
+ painter->setFont( font() );
+ painter->setPen( palette().color( QPalette::Text ) );
+
+ painter->translate( r.x(), r.y() );
+ if ( angle != 0.0 )
+ painter->rotate( angle );
+
+ QwtText title = d_data->title;
+ title.setRenderFlags( flags );
+ title.draw( painter, QRectF( 0.0, 0.0, r.width(), r.height() ) );
+
+ painter->restore();
+}
+
+/*!
+ \brief Notify a change of the scale
+
+ This virtual function can be overloaded by derived
+ classes. The default implementation updates the geometry
+ and repaints the widget.
+*/
+
+void QwtScaleWidget::scaleChange()
+{
+ layoutScale();
+}
+
+/*!
+ \return a size hint
+*/
+QSize QwtScaleWidget::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+/*!
+ \return a minimum size hint
+*/
+QSize QwtScaleWidget::minimumSizeHint() const
+{
+ const Qt::Orientation o = d_data->scaleDraw->orientation();
+
+ // Border Distance cannot be less than the scale borderDistHint
+ // Note, the borderDistHint is already included in minHeight/minWidth
+ int length = 0;
+ int mbd1, mbd2;
+ getBorderDistHint( mbd1, mbd2 );
+ length += qMax( 0, d_data->borderDist[0] - mbd1 );
+ length += qMax( 0, d_data->borderDist[1] - mbd2 );
+ length += d_data->scaleDraw->minLength( font() );
+
+ int dim = dimForLength( length, font() );
+ if ( length < dim )
+ {
+ // compensate for long titles
+ length = dim;
+ dim = dimForLength( length, font() );
+ }
+
+ QSize size( length + 2, dim );
+ if ( o == Qt::Vertical )
+ size.transpose();
+
+ int left, right, top, bottom;
+ getContentsMargins( &left, &top, &right, &bottom );
+ return size + QSize( left + right, top + bottom );
+}
+
+/*!
+ \brief Find the height of the title for a given width.
+ \param width Width
+ \return height Height
+ */
+
+int QwtScaleWidget::titleHeightForWidth( int width ) const
+{
+ return qCeil( d_data->title.heightForWidth( width, font() ) );
+}
+
+/*!
+ \brief Find the minimum dimension for a given length.
+ dim is the height, length the width seen in
+ direction of the title.
+ \param length width for horizontal, height for vertical scales
+ \param scaleFont Font of the scale
+ \return height for horizontal, width for vertical scales
+*/
+
+int QwtScaleWidget::dimForLength( int length, const QFont &scaleFont ) const
+{
+ const int extent = qCeil( d_data->scaleDraw->extent( scaleFont ) );
+
+ int dim = d_data->margin + extent + 1;
+
+ if ( !d_data->title.isEmpty() )
+ dim += titleHeightForWidth( length ) + d_data->spacing;
+
+ if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
+ dim += d_data->colorBar.width + d_data->spacing;
+
+ return dim;
+}
+
+/*!
+ \brief Calculate a hint for the border distances.
+
+ This member function calculates the distance
+ of the scale's endpoints from the widget borders which
+ is required for the mark labels to fit into the widget.
+ The maximum of this distance an the minimum border distance
+ is returned.
+
+ \warning
+ <ul> <li>The minimum border distance depends on the font.</ul>
+ \sa setMinBorderDist(), getMinBorderDist(), setBorderDist()
+*/
+void QwtScaleWidget::getBorderDistHint( int &start, int &end ) const
+{
+ d_data->scaleDraw->getBorderDistHint( font(), start, end );
+
+ if ( start < d_data->minBorderDist[0] )
+ start = d_data->minBorderDist[0];
+
+ if ( end < d_data->minBorderDist[1] )
+ end = d_data->minBorderDist[1];
+}
+
+/*!
+ Set a minimum value for the distances of the scale's endpoints from
+ the widget borders. This is useful to avoid that the scales
+ are "jumping", when the tick labels or their positions change
+ often.
+
+ \param start Minimum for the start border
+ \param end Minimum for the end border
+ \sa getMinBorderDist(), getBorderDistHint()
+*/
+void QwtScaleWidget::setMinBorderDist( int start, int end )
+{
+ d_data->minBorderDist[0] = start;
+ d_data->minBorderDist[1] = end;
+}
+
+/*!
+ Get the minimum value for the distances of the scale's endpoints from
+ the widget borders.
+
+ \sa setMinBorderDist(), getBorderDistHint()
+*/
+void QwtScaleWidget::getMinBorderDist( int &start, int &end ) const
+{
+ start = d_data->minBorderDist[0];
+ end = d_data->minBorderDist[1];
+}
+
+/*!
+ \brief Assign a scale division
+
+ The scale division determines where to set the tick marks.
+
+ \param transformation Transformation, needed to translate between
+ scale and pixal values
+ \param scaleDiv Scale Division
+ \sa For more information about scale divisions, see QwtScaleDiv.
+*/
+void QwtScaleWidget::setScaleDiv(
+ QwtScaleTransformation *transformation,
+ const QwtScaleDiv &scaleDiv )
+{
+ QwtScaleDraw *sd = d_data->scaleDraw;
+ if ( sd->scaleDiv() != scaleDiv ||
+ sd->scaleMap().transformation()->type() != transformation->type() )
+ {
+ sd->setTransformation( transformation );
+ sd->setScaleDiv( scaleDiv );
+ layoutScale();
+
+ Q_EMIT scaleDivChanged();
+ }
+ else
+ {
+ /*
+ The transformation doesn't anything different as the
+ previous one. So we better throw it silently away instead of
+ initiating heavy updates
+ */
+
+ delete transformation;
+ }
+}
+
+/*!
+ En/disable a color bar associated to the scale
+ \sa isColorBarEnabled(), setColorBarWidth()
+*/
+void QwtScaleWidget::setColorBarEnabled( bool on )
+{
+ if ( on != d_data->colorBar.isEnabled )
+ {
+ d_data->colorBar.isEnabled = on;
+ layoutScale();
+ }
+}
+
+/*!
+ \return true, when the color bar is enabled
+ \sa setColorBarEnabled(), setColorBarWidth()
+*/
+bool QwtScaleWidget::isColorBarEnabled() const
+{
+ return d_data->colorBar.isEnabled;
+}
+
+/*!
+ Set the width of the color bar
+
+ \param width Width
+ \sa colorBarWidth(), setColorBarEnabled()
+*/
+void QwtScaleWidget::setColorBarWidth( int width )
+{
+ if ( width != d_data->colorBar.width )
+ {
+ d_data->colorBar.width = width;
+ if ( isColorBarEnabled() )
+ layoutScale();
+ }
+}
+
+/*!
+ \return Width of the color bar
+ \sa setColorBarEnabled(), setColorBarEnabled()
+*/
+int QwtScaleWidget::colorBarWidth() const
+{
+ return d_data->colorBar.width;
+}
+
+/*!
+ \return Value interval for the color bar
+ \sa setColorMap(), colorMap()
+*/
+QwtInterval QwtScaleWidget::colorBarInterval() const
+{
+ return d_data->colorBar.interval;
+}
+
+/*!
+ Set the color map and value interval, that are used for displaying
+ the color bar.
+
+ \param interval Value interval
+ \param colorMap Color map
+
+ \sa colorMap(), colorBarInterval()
+*/
+void QwtScaleWidget::setColorMap(
+ const QwtInterval &interval, QwtColorMap *colorMap )
+{
+ d_data->colorBar.interval = interval;
+
+ if ( colorMap != d_data->colorBar.colorMap )
+ {
+ delete d_data->colorBar.colorMap;
+ d_data->colorBar.colorMap = colorMap;
+ }
+
+ if ( isColorBarEnabled() )
+ layoutScale();
+}
+
+/*!
+ \return Color map
+ \sa setColorMap(), colorBarInterval()
+*/
+const QwtColorMap *QwtScaleWidget::colorMap() const
+{
+ return d_data->colorBar.colorMap;
+}
diff --git a/src/libpcp_qwt/src/qwt_scale_widget.h b/src/libpcp_qwt/src/qwt_scale_widget.h
new file mode 100644
index 0000000..7007902
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_scale_widget.h
@@ -0,0 +1,135 @@
+/* -*- 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_SCALE_WIDGET_H
+#define QWT_SCALE_WIDGET_H
+
+#include "qwt_global.h"
+#include "qwt_text.h"
+#include "qwt_scale_draw.h"
+#include <qwidget.h>
+#include <qfont.h>
+#include <qcolor.h>
+#include <qstring.h>
+
+class QPainter;
+class QwtScaleTransformation;
+class QwtScaleDiv;
+class QwtColorMap;
+
+/*!
+ \brief A Widget which contains a scale
+
+ This Widget can be used to decorate composite widgets with
+ a scale.
+*/
+
+class QWT_EXPORT QwtScaleWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ //! Layout flags of the title
+ enum LayoutFlag
+ {
+ /*!
+ The title of vertical scales is painted from top to bottom.
+ Otherwise it is painted from bottom to top.
+ */
+ TitleInverted = 1
+ };
+
+ //! Layout flags of the title
+ typedef QFlags<LayoutFlag> LayoutFlags;
+
+ explicit QwtScaleWidget( QWidget *parent = NULL );
+ explicit QwtScaleWidget( QwtScaleDraw::Alignment, QWidget *parent = NULL );
+ virtual ~QwtScaleWidget();
+
+Q_SIGNALS:
+ //! Signal emitted, whenever the scale divison changes
+ void scaleDivChanged();
+
+public:
+ void setTitle( const QString &title );
+ void setTitle( const QwtText &title );
+ QwtText title() const;
+
+ void setLayoutFlag( LayoutFlag, bool on );
+ bool testLayoutFlag( LayoutFlag ) const;
+
+ void setBorderDist( int start, int end );
+ int startBorderDist() const;
+ int endBorderDist() const;
+
+ void getBorderDistHint( int &start, int &end ) const;
+
+ void getMinBorderDist( int &start, int &end ) const;
+ void setMinBorderDist( int start, int end );
+
+ void setMargin( int );
+ int margin() const;
+
+ void setSpacing( int td );
+ int spacing() const;
+
+ void setScaleDiv( QwtScaleTransformation *, const QwtScaleDiv &sd );
+
+ void setScaleDraw( QwtScaleDraw * );
+ const QwtScaleDraw *scaleDraw() const;
+ QwtScaleDraw *scaleDraw();
+
+ void setLabelAlignment( Qt::Alignment );
+ void setLabelRotation( double rotation );
+
+ void setColorBarEnabled( bool );
+ bool isColorBarEnabled() const;
+
+ void setColorBarWidth( int );
+ int colorBarWidth() const;
+
+ void setColorMap( const QwtInterval &, QwtColorMap * );
+
+ QwtInterval colorBarInterval() const;
+ const QwtColorMap *colorMap() const;
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ int titleHeightForWidth( int width ) const;
+ int dimForLength( int length, const QFont &scaleFont ) const;
+
+ void drawColorBar( QPainter *painter, const QRectF & ) const;
+ void drawTitle( QPainter *painter, QwtScaleDraw::Alignment,
+ const QRectF &rect ) const;
+
+ void setAlignment( QwtScaleDraw::Alignment );
+ QwtScaleDraw::Alignment alignment() const;
+
+ QRectF colorBarRect( const QRectF& ) const;
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ void draw( QPainter *p ) const;
+
+ void scaleChange();
+ void layoutScale( bool update = true );
+
+private:
+ void initScale( QwtScaleDraw::Alignment );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtScaleWidget::LayoutFlags )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_series_data.cpp b/src/libpcp_qwt/src/qwt_series_data.cpp
new file mode 100644
index 0000000..faf7fc8
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_series_data.cpp
@@ -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_series_data.h"
+#include "qwt_math.h"
+#include <qnumeric.h>
+
+static inline QRectF qwtBoundingRect( const QPointF &sample )
+{
+ return QRectF( sample.x(), sample.y(), 0.0, 0.0 );
+}
+
+static inline QRectF qwtBoundingRect( const QwtPoint3D &sample )
+{
+ return QRectF( sample.x(), sample.y(), 0.0, 0.0 );
+}
+
+static inline QRectF qwtBoundingRect( const QwtPointPolar &sample )
+{
+ return QRectF( sample.azimuth(), sample.radius(), 0.0, 0.0 );
+}
+
+static inline QRectF qwtBoundingRect( const QwtIntervalSample &sample )
+{
+ return QRectF( sample.interval.minValue(), sample.value,
+ sample.interval.maxValue() - sample.interval.minValue(), 0.0 );
+}
+
+static inline QRectF qwtBoundingRect( const QwtSetSample &sample )
+{
+ double minX = sample.set[0];
+ double maxX = sample.set[0];
+
+ for ( int i = 1; i < sample.set.size(); i++ )
+ {
+ if ( sample.set[i] < minX )
+ minX = sample.set[i];
+ if ( sample.set[i] > maxX )
+ maxX = sample.set[i];
+ }
+
+ double minY = sample.value;
+ double maxY = sample.value;
+
+ return QRectF( minX, minY, maxX - minX, maxY - minY );
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+
+template <class T>
+QRectF qwtBoundingRectT(
+ const QwtSeriesData<T>& series, int from, int to )
+{
+ QRectF boundingRect( 1.0, 1.0, -2.0, -2.0 ); // invalid;
+
+ if ( from < 0 )
+ from = 0;
+
+ if ( to < 0 )
+ to = series.size() - 1;
+
+ if ( to < from )
+ return boundingRect;
+
+ int i;
+ for ( i = from; i <= to; i++ )
+ {
+ const QRectF rect = qwtBoundingRect( series.sample( i ) );
+ if ( rect.width() >= 0.0 && rect.height() >= 0.0 )
+ {
+ boundingRect = rect;
+ i++;
+ break;
+ }
+ }
+
+ for ( ; i <= to; i++ )
+ {
+ const QRectF rect = qwtBoundingRect( series.sample( i ) );
+ if ( rect.width() >= 0.0 && rect.height() >= 0.0 )
+ {
+ if (!qIsNaN(rect.left()))
+ boundingRect.setLeft( qMin( boundingRect.left(), rect.left() ) );
+ if (!qIsNaN(rect.right()))
+ boundingRect.setRight( qMax( boundingRect.right(), rect.right() ) );
+ if (!qIsNaN(rect.top()))
+ boundingRect.setTop( qMin( boundingRect.top(), rect.top() ) );
+ if (!qIsNaN(rect.bottom()))
+ boundingRect.setBottom( qMax( boundingRect.bottom(), rect.bottom() ) );
+ }
+ }
+
+ return boundingRect;
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+QRectF qwtBoundingRect(
+ const QwtSeriesData<QPointF> &series, int from, int to )
+{
+ return qwtBoundingRectT<QPointF>( series, from, to );
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtPoint3D> &series, int from, int to )
+{
+ return qwtBoundingRectT<QwtPoint3D>( series, from, to );
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ The horizontal coordinates represent the azimuth, the
+ vertical coordinates the radius.
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtPointPolar> &series, int from, int to )
+{
+ return qwtBoundingRectT<QwtPointPolar>( series, from, to );
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtIntervalSample>& series, int from, int to )
+{
+ return qwtBoundingRectT<QwtIntervalSample>( series, from, to );
+}
+
+/*!
+ \brief Calculate the bounding rect of a series subset
+
+ Slow implementation, that iterates over the series.
+
+ \param series Series
+ \param from Index of the first sample, <= 0 means from the beginning
+ \param to Index of the last sample, < 0 means to the end
+
+ \return Bounding rectangle
+*/
+QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtSetSample>& series, int from, int to )
+{
+ return qwtBoundingRectT<QwtSetSample>( series, from, to );
+}
+
+/*!
+ Constructor
+ \param samples Samples
+*/
+QwtPointSeriesData::QwtPointSeriesData(
+ const QVector<QPointF> &samples ):
+ QwtArraySeriesData<QPointF>( samples )
+{
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtPointSeriesData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0.0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+/*!
+ Constructor
+ \param samples Samples
+*/
+QwtPoint3DSeriesData::QwtPoint3DSeriesData(
+ const QVector<QwtPoint3D> &samples ):
+ QwtArraySeriesData<QwtPoint3D>( samples )
+{
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtPoint3DSeriesData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0.0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+/*!
+ Constructor
+ \param samples Samples
+*/
+QwtIntervalSeriesData::QwtIntervalSeriesData(
+ const QVector<QwtIntervalSample> &samples ):
+ QwtArraySeriesData<QwtIntervalSample>( samples )
+{
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtIntervalSeriesData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0.0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+/*!
+ Constructor
+ \param samples Samples
+*/
+QwtSetSeriesData::QwtSetSeriesData(
+ const QVector<QwtSetSample> &samples ):
+ QwtArraySeriesData<QwtSetSample>( samples )
+{
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtSetSeriesData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0.0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+/*!
+ Constructor
+
+ \param x Array of x values
+ \param y Array of y values
+
+ \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples()
+*/
+QwtPointArrayData::QwtPointArrayData(
+ const QVector<double> &x, const QVector<double> &y ):
+ d_x( x ),
+ d_y( y )
+{
+}
+
+/*!
+ Constructor
+
+ \param x Array of x values
+ \param y Array of y values
+ \param size Size of the x and y arrays
+ \sa QwtPlotCurve::setData(), QwtPlotCurve::setSamples()
+*/
+QwtPointArrayData::QwtPointArrayData( const double *x,
+ const double *y, size_t size )
+{
+ d_x.resize( size );
+ qMemCopy( d_x.data(), x, size * sizeof( double ) );
+
+ d_y.resize( size );
+ qMemCopy( d_y.data(), y, size * sizeof( double ) );
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtPointArrayData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+//! \return Size of the data set
+size_t QwtPointArrayData::size() const
+{
+ return qMin( d_x.size(), d_y.size() );
+}
+
+/*!
+ Return the sample at position i
+
+ \param i Index
+ \return Sample at position i
+*/
+QPointF QwtPointArrayData::sample( size_t i ) const
+{
+ return QPointF( d_x[int( i )], d_y[int( i )] );
+}
+
+//! \return Array of the x-values
+const QVector<double> &QwtPointArrayData::xData() const
+{
+ return d_x;
+}
+
+//! \return Array of the y-values
+const QVector<double> &QwtPointArrayData::yData() const
+{
+ return d_y;
+}
+
+/*!
+ Constructor
+
+ \param x Array of x values
+ \param y Array of y values
+ \param size Size of the x and y arrays
+
+ \warning The programmer must assure that the memory blocks referenced
+ by the pointers remain valid during the lifetime of the
+ QwtPlotCPointer object.
+
+ \sa QwtPlotCurve::setData(), QwtPlotCurve::setRawSamples()
+*/
+QwtCPointerData::QwtCPointerData(
+ const double *x, const double *y, size_t size ):
+ d_x( x ),
+ d_y( y ),
+ d_size( size )
+{
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ The bounding rectangle is calculated once by iterating over all
+ points and is stored for all following requests.
+
+ \return Bounding rectangle
+*/
+QRectF QwtCPointerData::boundingRect() const
+{
+ if ( d_boundingRect.width() < 0 )
+ d_boundingRect = qwtBoundingRect( *this );
+
+ return d_boundingRect;
+}
+
+//! \return Size of the data set
+size_t QwtCPointerData::size() const
+{
+ return d_size;
+}
+
+/*!
+ Return the sample at position i
+
+ \param i Index
+ \return Sample at position i
+*/
+QPointF QwtCPointerData::sample( size_t i ) const
+{
+ return QPointF( d_x[int( i )], d_y[int( i )] );
+}
+
+//! \return Array of the x-values
+const double *QwtCPointerData::xData() const
+{
+ return d_x;
+}
+
+//! \return Array of the y-values
+const double *QwtCPointerData::yData() const
+{
+ return d_y;
+}
+
+/*!
+ Constructor
+
+ \param size Number of points
+ \param interval Bounding interval for the points
+
+ \sa setInterval(), setSize()
+*/
+QwtSyntheticPointData::QwtSyntheticPointData(
+ size_t size, const QwtInterval &interval ):
+ d_size( size ),
+ d_interval( interval )
+{
+}
+
+/*!
+ Change the number of points
+
+ \param size Number of points
+ \sa size(), setInterval()
+*/
+void QwtSyntheticPointData::setSize( size_t size )
+{
+ d_size = size;
+}
+
+/*!
+ \return Number of points
+ \sa setSize(), interval()
+*/
+size_t QwtSyntheticPointData::size() const
+{
+ return d_size;
+}
+
+/*!
+ Set the bounding interval
+
+ \param interval Interval
+ \sa interval(), setSize()
+*/
+void QwtSyntheticPointData::setInterval( const QwtInterval &interval )
+{
+ d_interval = interval.normalized();
+}
+
+/*!
+ \return Bounding interval
+ \sa setInterval(), size()
+*/
+QwtInterval QwtSyntheticPointData::interval() const
+{
+ return d_interval;
+}
+
+/*!
+ Set a the "rect of interest"
+
+ QwtPlotSeriesItem defines the current area of the plot canvas
+ as "rect of interest" ( QwtPlotSeriesItem::updateScaleDiv() ).
+
+ If interval().isValid() == false the x values are calculated
+ in the interval rect.left() -> rect.right().
+
+ \sa rectOfInterest()
+*/
+void QwtSyntheticPointData::setRectOfInterest( const QRectF &rect )
+{
+ d_rectOfInterest = rect;
+ d_intervalOfInterest = QwtInterval(
+ rect.left(), rect.right() ).normalized();
+}
+
+/*!
+ \return "rect of interest"
+ \sa setRectOfInterest()
+*/
+QRectF QwtSyntheticPointData::rectOfInterest() const
+{
+ return d_rectOfInterest;
+}
+
+/*!
+ \brief Calculate the bounding rect
+
+ This implementation iterates over all points, what could often
+ be implemented much faster using the characteristics of the series.
+ When there are many points it is recommended to overload and
+ reimplement this method using the characteristics of the series
+ ( if possible ).
+
+ \return Bounding rectangle
+*/
+QRectF QwtSyntheticPointData::boundingRect() const
+{
+ if ( d_size == 0 ||
+ !( d_interval.isValid() || d_intervalOfInterest.isValid() ) )
+ {
+ return QRectF( 1.0, 1.0, -2.0, -2.0 ); // something invalid
+ }
+
+ return qwtBoundingRect( *this );
+}
+
+/*!
+ Calculate the point from an index
+
+ \param index Index
+ \return QPointF(x(index), y(x(index)));
+
+ \warning For invalid indices ( index < 0 || index >= size() )
+ (0, 0) is returned.
+*/
+QPointF QwtSyntheticPointData::sample( size_t index ) const
+{
+ if ( index >= d_size )
+ return QPointF( 0, 0 );
+
+ const double xValue = x( index );
+ const double yValue = y( xValue );
+
+ return QPointF( xValue, yValue );
+}
+
+/*!
+ Calculate a x-value from an index
+
+ x values are calculated by deviding an interval into
+ equidistant steps. If !interval().isValid() the
+ interval is calculated from the "rect of interest".
+
+ \sa interval(), rectOfInterest(), y()
+*/
+double QwtSyntheticPointData::x( uint index ) const
+{
+ const QwtInterval &interval = d_interval.isValid() ?
+ d_interval : d_intervalOfInterest;
+
+ if ( !interval.isValid() || d_size == 0 || index >= d_size )
+ return 0.0;
+
+ const double dx = interval.width() / d_size;
+ return interval.minValue() + index * dx;
+}
diff --git a/src/libpcp_qwt/src/qwt_series_data.h b/src/libpcp_qwt/src/qwt_series_data.h
new file mode 100644
index 0000000..cf4a8d2
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_series_data.h
@@ -0,0 +1,460 @@
+/* -*- 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_SERIES_DATA_H
+#define QWT_SERIES_DATA_H 1
+
+#include "qwt_global.h"
+#include "qwt_interval.h"
+#include "qwt_point_3d.h"
+#include "qwt_point_polar.h"
+#include <qvector.h>
+#include <qrect.h>
+
+//! \brief A sample of the types (x1-x2, y) or (x, y1-y2)
+class QWT_EXPORT QwtIntervalSample
+{
+public:
+ QwtIntervalSample();
+ QwtIntervalSample( double, const QwtInterval & );
+ QwtIntervalSample( double value, double min, double max );
+
+ bool operator==( const QwtIntervalSample & ) const;
+ bool operator!=( const QwtIntervalSample & ) const;
+
+ //! Value
+ double value;
+
+ //! Interval
+ QwtInterval interval;
+};
+
+/*!
+ Constructor
+ The value is set to 0.0, the interval is invalid
+*/
+inline QwtIntervalSample::QwtIntervalSample():
+ value( 0.0 )
+{
+}
+
+//! Constructor
+inline QwtIntervalSample::QwtIntervalSample(
+ double v, const QwtInterval &intv ):
+ value( v ),
+ interval( intv )
+{
+}
+
+//! Constructor
+inline QwtIntervalSample::QwtIntervalSample(
+ double v, double min, double max ):
+ value( v ),
+ interval( min, max )
+{
+}
+
+//! Compare operator
+inline bool QwtIntervalSample::operator==(
+ const QwtIntervalSample &other ) const
+{
+ return value == other.value && interval == other.interval;
+}
+
+//! Compare operator
+inline bool QwtIntervalSample::operator!=(
+ const QwtIntervalSample &other ) const
+{
+ return !( *this == other );
+}
+
+//! \brief A sample of the types (x1...xn, y) or (x, y1..yn)
+class QWT_EXPORT QwtSetSample
+{
+public:
+ QwtSetSample();
+ bool operator==( const QwtSetSample &other ) const;
+ bool operator!=( const QwtSetSample &other ) const;
+
+ //! value
+ double value;
+
+ //! Vector of values associated to value
+ QVector<double> set;
+};
+
+/*!
+ Constructor
+ The value is set to 0.0
+*/
+inline QwtSetSample::QwtSetSample():
+ value( 0.0 )
+{
+}
+
+//! Compare operator
+inline bool QwtSetSample::operator==( const QwtSetSample &other ) const
+{
+ return value == other.value && set == other.set;
+}
+
+//! Compare operator
+inline bool QwtSetSample::operator!=( const QwtSetSample &other ) const
+{
+ return !( *this == other );
+}
+
+/*!
+ \brief Abstract interface for iterating over samples
+
+ Qwt offers several implementations of the QwtSeriesData API,
+ but in situations, where data of an application specific format
+ needs to be displayed, without having to copy it, it is recommended
+ to implement an individual data access.
+
+ A subclass of QwtSeriesData<QPointF> must implement:
+
+ - size()\n
+ Should return number of data points.
+
+ - sample()\n
+ Should return values x and y values of the sample at specific position
+ as QPointF object.
+
+ - boundingRect()\n
+ Should return the bounding rectangle of the data series.
+ It is used for autoscaling and might help certain algorithms for displaying
+ the data. You can use qwtBoundingRect() for an implementation
+ but often it is possible to implement a more efficient alogrithm
+ depending on the characteristics of the series.
+ The member d_boundingRect is intended for caching the calculated rectangle.
+
+*/
+template <typename T>
+class QwtSeriesData
+{
+public:
+ QwtSeriesData();
+ virtual ~QwtSeriesData();
+
+ //! \return Number of samples
+ virtual size_t size() const = 0;
+
+ /*!
+ Return a sample
+ \param i Index
+ \return Sample at position i
+ */
+ virtual T sample( size_t i ) const = 0;
+
+ /*!
+ Calculate the bounding rect of all samples
+
+ The bounding rect is necessary for autoscaling and can be used
+ for a couple of painting optimizations.
+
+ qwtBoundingRect(...) offers slow implementations iterating
+ over the samples. For large sets it is recommended to implement
+ something faster f.e. by caching the bounding rect.
+ */
+ virtual QRectF boundingRect() const = 0;
+
+ virtual void setRectOfInterest( const QRectF & );
+
+protected:
+ //! Can be used to cache a calculated bounding rectangle
+ mutable QRectF d_boundingRect;
+
+private:
+ QwtSeriesData<T> &operator=( const QwtSeriesData<T> & );
+};
+
+//! Constructor
+template <typename T>
+QwtSeriesData<T>::QwtSeriesData():
+ d_boundingRect( 0.0, 0.0, -1.0, -1.0 )
+{
+}
+
+//! Destructor
+template <typename T>
+QwtSeriesData<T>::~QwtSeriesData()
+{
+}
+
+/*!
+ Set a the "rect of interest"
+
+ QwtPlotSeriesItem defines the current area of the plot canvas
+ as "rect of interest" ( QwtPlotSeriesItem::updateScaleDiv() ).
+ It can be used to implement different levels of details.
+
+ The default implementation does nothing.
+*/
+template <typename T>
+void QwtSeriesData<T>::setRectOfInterest( const QRectF & )
+{
+}
+
+/*!
+ \brief Template class for data, that is organized as QVector
+
+ QVector uses implicit data sharing and can be
+ passed around as argument efficiently.
+*/
+template <typename T>
+class QwtArraySeriesData: public QwtSeriesData<T>
+{
+public:
+ QwtArraySeriesData();
+ QwtArraySeriesData( const QVector<T> & );
+
+ void setSamples( const QVector<T> & );
+ const QVector<T> samples() const;
+
+ virtual size_t size() const;
+ virtual T sample( size_t ) const;
+
+protected:
+ //! Vector of samples
+ QVector<T> d_samples;
+};
+
+//! Constructor
+template <typename T>
+QwtArraySeriesData<T>::QwtArraySeriesData()
+{
+}
+
+/*!
+ Constructor
+ \param samples Array of samples
+*/
+template <typename T>
+QwtArraySeriesData<T>::QwtArraySeriesData( const QVector<T> &samples ):
+ d_samples( samples )
+{
+}
+
+/*!
+ Assign an array of samples
+ \param samples Array of samples
+*/
+template <typename T>
+void QwtArraySeriesData<T>::setSamples( const QVector<T> &samples )
+{
+ QwtSeriesData<T>::d_boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
+ d_samples = samples;
+}
+
+//! \return Array of samples
+template <typename T>
+const QVector<T> QwtArraySeriesData<T>::samples() const
+{
+ return d_samples;
+}
+
+//! \return Number of samples
+template <typename T>
+size_t QwtArraySeriesData<T>::size() const
+{
+ return d_samples.size();
+}
+
+/*!
+ Return a sample
+ \param i Index
+ \return Sample at position i
+*/
+template <typename T>
+T QwtArraySeriesData<T>::sample( size_t i ) const
+{
+ return d_samples[ static_cast<int>( i ) ];
+}
+
+//! Interface for iterating over an array of points
+class QWT_EXPORT QwtPointSeriesData: public QwtArraySeriesData<QPointF>
+{
+public:
+ QwtPointSeriesData(
+ const QVector<QPointF> & = QVector<QPointF>() );
+
+ virtual QRectF boundingRect() const;
+};
+
+//! Interface for iterating over an array of 3D points
+class QWT_EXPORT QwtPoint3DSeriesData: public QwtArraySeriesData<QwtPoint3D>
+{
+public:
+ QwtPoint3DSeriesData(
+ const QVector<QwtPoint3D> & = QVector<QwtPoint3D>() );
+ virtual QRectF boundingRect() const;
+};
+
+//! Interface for iterating over an array of intervals
+class QWT_EXPORT QwtIntervalSeriesData: public QwtArraySeriesData<QwtIntervalSample>
+{
+public:
+ QwtIntervalSeriesData(
+ const QVector<QwtIntervalSample> & = QVector<QwtIntervalSample>() );
+
+ virtual QRectF boundingRect() const;
+};
+
+//! Interface for iterating over an array of samples
+class QWT_EXPORT QwtSetSeriesData: public QwtArraySeriesData<QwtSetSample>
+{
+public:
+ QwtSetSeriesData(
+ const QVector<QwtSetSample> & = QVector<QwtSetSample>() );
+
+ virtual QRectF boundingRect() const;
+};
+
+/*!
+ \brief Interface for iterating over two QVector<double> objects.
+*/
+class QWT_EXPORT QwtPointArrayData: public QwtSeriesData<QPointF>
+{
+public:
+ QwtPointArrayData( const QVector<double> &x, const QVector<double> &y );
+ QwtPointArrayData( const double *x, const double *y, size_t size );
+
+ virtual QRectF boundingRect() const;
+
+ virtual size_t size() const;
+ virtual QPointF sample( size_t i ) const;
+
+ const QVector<double> &xData() const;
+ const QVector<double> &yData() const;
+
+private:
+ QVector<double> d_x;
+ QVector<double> d_y;
+};
+
+/*!
+ \brief Data class containing two pointers to memory blocks of doubles.
+ */
+class QWT_EXPORT QwtCPointerData: public QwtSeriesData<QPointF>
+{
+public:
+ QwtCPointerData( const double *x, const double *y, size_t size );
+
+ virtual QRectF boundingRect() const;
+ virtual size_t size() const;
+ virtual QPointF sample( size_t i ) const;
+
+ const double *xData() const;
+ const double *yData() const;
+
+private:
+ const double *d_x;
+ const double *d_y;
+ size_t d_size;
+};
+
+/*!
+ \brief Synthetic point data
+
+ QwtSyntheticPointData provides a fixed number of points for an interval.
+ The points are calculated in equidistant steps in x-direction.
+
+ If the interval is invalid, the points are calculated for
+ the "rect of interest", what normally is the displayed area on the
+ plot canvas. In this mode you get different levels of detail, when
+ zooming in/out.
+
+ \par Example
+
+ The following example shows how to implement a sinus curve.
+
+ \verbatim
+#include <cmath>
+#include <qwt_series_data.h>
+#include <qwt_plot_curve.h>
+#include <qwt_plot.h>
+#include <qapplication.h>
+
+class SinusData: public QwtSyntheticPointData
+{
+public:
+ SinusData():
+ QwtSyntheticPointData(100)
+ {
+ }
+ virtual double y(double x) const
+ {
+ return qSin(x);
+ }
+};
+
+int main(int argc, char **argv)
+{
+ QApplication a(argc, argv);
+
+ QwtPlot plot;
+ plot.setAxisScale(QwtPlot::xBottom, 0.0, 10.0);
+ plot.setAxisScale(QwtPlot::yLeft, -1.0, 1.0);
+
+ QwtPlotCurve *curve = new QwtPlotCurve("y = sin(x)");
+ curve->setData(SinusData());
+ curve->attach(&plot);
+
+ plot.show();
+ return a.exec();
+}
+ \endverbatim
+*/
+class QWT_EXPORT QwtSyntheticPointData: public QwtSeriesData<QPointF>
+{
+public:
+ QwtSyntheticPointData( size_t size,
+ const QwtInterval & = QwtInterval() );
+
+ void setSize( size_t size );
+ size_t size() const;
+
+ void setInterval( const QwtInterval& );
+ QwtInterval interval() const;
+
+ virtual QRectF boundingRect() const;
+ virtual QPointF sample( size_t i ) const;
+
+ /*!
+ Calculate a y value for a x value
+
+ \param x x value
+ \return Corresponding y value
+ */
+ virtual double y( double x ) const = 0;
+ virtual double x( uint index ) const;
+
+ virtual void setRectOfInterest( const QRectF & );
+ QRectF rectOfInterest() const;
+
+private:
+ size_t d_size;
+ QwtInterval d_interval;
+ QRectF d_rectOfInterest;
+ QwtInterval d_intervalOfInterest;
+};
+
+QWT_EXPORT QRectF qwtBoundingRect(
+ const QwtSeriesData<QPointF> &, int from = 0, int to = -1 );
+QWT_EXPORT QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtPoint3D> &, int from = 0, int to = -1 );
+QWT_EXPORT QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtPointPolar> &, int from = 0, int to = -1 );
+QWT_EXPORT QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtIntervalSample> &, int from = 0, int to = -1 );
+QWT_EXPORT QRectF qwtBoundingRect(
+ const QwtSeriesData<QwtSetSample> &, int from = 0, int to = -1 );
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_slider.cpp b/src/libpcp_qwt/src/qwt_slider.cpp
new file mode 100644
index 0000000..357f920
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_slider.cpp
@@ -0,0 +1,805 @@
+/* -*- 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_slider.h"
+#include "qwt_painter.h"
+#include "qwt_scale_draw.h"
+#include "qwt_scale_map.h"
+#include <qevent.h>
+#include <qdrawutil.h>
+#include <qpainter.h>
+#include <qalgorithms.h>
+#include <qmath.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qapplication.h>
+
+class QwtSlider::PrivateData
+{
+public:
+ QRect sliderRect;
+
+ QSize handleSize;
+ int borderWidth;
+ int spacing;
+
+ QwtSlider::ScalePos scalePos;
+ QwtSlider::BackgroundStyles bgStyle;
+
+ /*
+ Scale and values might have different maps. This is
+ confusing and I can't see strong arguments for such
+ a feature. TODO ...
+ */
+ QwtScaleMap map; // linear map
+ mutable QSize sizeHintCache;
+};
+
+/*!
+ \brief Constructor
+ \param parent parent widget
+ \param orientation Orientation of the slider. Can be Qt::Horizontal
+ or Qt::Vertical. Defaults to Qt::Horizontal.
+ \param scalePos Position of the scale.
+ Defaults to QwtSlider::NoScale.
+ \param bgStyle Background style. QwtSlider::Trough draws the
+ slider button in a trough, QwtSlider::Slot draws
+ a slot underneath the button. An or-combination of both
+ may also be used. The default is QwtSlider::Trough.
+
+ QwtSlider enforces valid combinations of its orientation and scale position.
+ If the combination is invalid, the scale position will be set to NoScale.
+ Valid combinations are:
+ - Qt::Horizonal with NoScale, TopScale, or BottomScale;
+ - Qt::Vertical with NoScale, LeftScale, or RightScale.
+*/
+QwtSlider::QwtSlider( QWidget *parent,
+ Qt::Orientation orientation, ScalePos scalePos,
+ BackgroundStyles bgStyle ):
+ QwtAbstractSlider( orientation, parent )
+{
+ initSlider( orientation, scalePos, bgStyle );
+}
+
+void QwtSlider::initSlider( Qt::Orientation orientation,
+ ScalePos scalePos, BackgroundStyles bgStyle )
+{
+ if ( orientation == Qt::Vertical )
+ setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
+ else
+ setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+
+ d_data = new QwtSlider::PrivateData;
+
+ d_data->borderWidth = 2;
+ d_data->spacing = 4;
+ d_data->scalePos = scalePos;
+ d_data->bgStyle = bgStyle;
+
+ const int handleThickness = 16;
+ d_data->handleSize.setWidth( 2 * handleThickness );
+ d_data->handleSize.setHeight( handleThickness );
+
+ if ( !( bgStyle & QwtSlider::Trough ) )
+ d_data->handleSize.transpose();
+
+ if ( orientation == Qt::Vertical )
+ d_data->handleSize.transpose();
+
+ d_data->sliderRect.setRect( 0, 0, 8, 8 );
+
+ QwtScaleDraw::Alignment align;
+ if ( orientation == Qt::Vertical )
+ {
+ // enforce a valid combination of scale position and orientation
+ if ( ( d_data->scalePos == QwtSlider::BottomScale )
+ || ( d_data->scalePos == QwtSlider::TopScale ) )
+ {
+ d_data->scalePos = NoScale;
+ }
+
+ // adopt the policy of layoutSlider (NoScale lays out like Left)
+ if ( d_data->scalePos == QwtSlider::RightScale )
+ align = QwtScaleDraw::RightScale;
+ else
+ align = QwtScaleDraw::LeftScale;
+ }
+ else
+ {
+ // enforce a valid combination of scale position and orientation
+ if ( ( d_data->scalePos == QwtSlider::LeftScale )
+ || ( d_data->scalePos == QwtSlider::RightScale ) )
+ {
+ d_data->scalePos = QwtSlider::NoScale;
+ }
+
+ // adopt the policy of layoutSlider (NoScale lays out like Bottom)
+ if ( d_data->scalePos == QwtSlider::TopScale )
+ align = QwtScaleDraw::TopScale;
+ else
+ align = QwtScaleDraw::BottomScale;
+ }
+
+ scaleDraw()->setAlignment( align );
+ scaleDraw()->setLength( 100 );
+
+ setRange( 0.0, 100.0, 1.0 );
+ setValue( 0.0 );
+}
+
+QwtSlider::~QwtSlider()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Set the orientation.
+ \param o Orientation. Allowed values are Qt::Horizontal and Qt::Vertical.
+
+ If the new orientation and the old scale position are an invalid combination,
+ the scale position will be set to QwtSlider::NoScale.
+ \sa QwtAbstractSlider::orientation()
+*/
+void QwtSlider::setOrientation( Qt::Orientation o )
+{
+ if ( o == orientation() )
+ return;
+
+ if ( o == Qt::Horizontal )
+ {
+ if ( d_data->scalePos == LeftScale
+ || d_data->scalePos == RightScale )
+ {
+ d_data->scalePos = NoScale;
+ }
+ }
+ else // if (o == Qt::Vertical)
+ {
+ if ( d_data->scalePos == BottomScale ||
+ d_data->scalePos == TopScale )
+ {
+ d_data->scalePos = NoScale;
+ }
+ }
+
+ if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
+ {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+ }
+
+ QwtAbstractSlider::setOrientation( o );
+ layoutSlider( true );
+}
+
+/*!
+ \brief Change the scale position (and slider orientation).
+
+ \param scalePos Position of the scale.
+
+ A valid combination of scale position and orientation is enforced:
+ - if the new scale position is Left or Right, the scale orientation will
+ become Qt::Vertical;
+ - if the new scale position is Bottom or Top the scale orientation will
+ become Qt::Horizontal;
+ - if the new scale position is QwtSlider::NoScale, the scale
+ orientation will not change.
+*/
+void QwtSlider::setScalePosition( ScalePos scalePos )
+{
+ if ( d_data->scalePos == scalePos )
+ return;
+
+ d_data->scalePos = scalePos;
+
+ switch ( d_data->scalePos )
+ {
+ case QwtSlider::BottomScale:
+ {
+ setOrientation( Qt::Horizontal );
+ scaleDraw()->setAlignment( QwtScaleDraw::BottomScale );
+ break;
+ }
+ case QwtSlider::TopScale:
+ {
+ setOrientation( Qt::Horizontal );
+ scaleDraw()->setAlignment( QwtScaleDraw::TopScale );
+ break;
+ }
+ case QwtSlider::LeftScale:
+ {
+ setOrientation( Qt::Vertical );
+ scaleDraw()->setAlignment( QwtScaleDraw::LeftScale );
+ break;
+ }
+ case RightScale:
+ {
+ QwtSlider::setOrientation( Qt::Vertical );
+ scaleDraw()->setAlignment( QwtScaleDraw::RightScale );
+ break;
+ }
+ default:
+ {
+ // nothing
+ }
+ }
+
+ layoutSlider( true );
+}
+
+//! Return the scale position.
+QwtSlider::ScalePos QwtSlider::scalePosition() const
+{
+ return d_data->scalePos;
+}
+
+/*!
+ \brief Change the slider's border width
+ \param width Border width
+*/
+void QwtSlider::setBorderWidth( int width )
+{
+ if ( width < 0 )
+ width = 0;
+
+ if ( width != d_data->borderWidth )
+ {
+ d_data->borderWidth = width;
+ layoutSlider( true );
+ }
+}
+
+/*!
+ \return the border width.
+ \sa setBorderWidth()
+*/
+int QwtSlider::borderWidth() const
+{
+ return d_data->borderWidth;
+}
+
+/*!
+ \brief Change the spacing between pipe and scale
+
+ A spacing of 0 means, that the backbone of the scale is below
+ the trough.
+
+ The default setting is 4 pixels.
+
+ \param spacing Number of pixels
+ \sa spacing();
+*/
+void QwtSlider::setSpacing( int spacing )
+{
+ if ( spacing <= 0 )
+ spacing = 0;
+
+ if ( spacing != d_data->spacing )
+ {
+ d_data->spacing = spacing;
+ layoutSlider( true );
+ }
+}
+
+/*!
+ \return Number of pixels between slider and scale
+ \sa setSpacing()
+*/
+int QwtSlider::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ \brief Set the slider's handle size
+ \param width Width
+ \param height Height
+
+ \sa handleSize()
+*/
+void QwtSlider::setHandleSize( int width, int height )
+{
+ setHandleSize( QSize( width, height ) );
+}
+
+/*!
+ \brief Set the slider's handle size
+ \param size New size
+
+ \sa handleSize()
+*/
+void QwtSlider::setHandleSize( const QSize &size )
+{
+ const QSize handleSize = size.expandedTo( QSize( 8, 4 ) );
+ if ( handleSize != d_data->handleSize )
+ {
+ d_data->handleSize = handleSize;
+ layoutSlider( true );
+ }
+}
+
+/*!
+ \return Size of the handle.
+ \sa setHandleSize()
+*/
+QSize QwtSlider::handleSize() const
+{
+ return d_data->handleSize;
+}
+
+/*!
+ \brief Set a scale draw
+
+ For changing the labels of the scales, it
+ is necessary to derive from QwtScaleDraw and
+ overload QwtScaleDraw::label().
+
+ \param scaleDraw ScaleDraw object, that has to be created with
+ new and will be deleted in ~QwtSlider or the next
+ call of setScaleDraw().
+
+ \sa scaleDraw()
+*/
+void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw )
+{
+ const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
+ if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
+ return;
+
+ if ( previousScaleDraw )
+ scaleDraw->setAlignment( previousScaleDraw->alignment() );
+
+ setAbstractScaleDraw( scaleDraw );
+ layoutSlider( true );
+}
+
+/*!
+ \return the scale draw of the slider
+ \sa setScaleDraw()
+*/
+const QwtScaleDraw *QwtSlider::scaleDraw() const
+{
+ return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
+}
+
+/*!
+ \return the scale draw of the slider
+ \sa setScaleDraw()
+*/
+QwtScaleDraw *QwtSlider::scaleDraw()
+{
+ return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
+}
+
+//! Notify changed scale
+void QwtSlider::scaleChange()
+{
+ layoutSlider( true );
+}
+
+/*!
+ Draw the slider into the specified rectangle.
+
+ \param painter Painter
+ \param sliderRect Bounding rectangle of the slider
+*/
+void QwtSlider::drawSlider(
+ QPainter *painter, const QRect &sliderRect ) const
+{
+ QRect innerRect( sliderRect );
+
+ if ( d_data->bgStyle & QwtSlider::Trough )
+ {
+ const int bw = d_data->borderWidth;
+
+ qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL );
+
+ innerRect = sliderRect.adjusted( bw, bw, -bw, -bw );
+ painter->fillRect( innerRect, palette().brush( QPalette::Mid ) );
+ }
+
+ if ( d_data->bgStyle & QwtSlider::Groove )
+ {
+ int ws = 4;
+ int ds = d_data->handleSize.width() / 2 - 4;
+ if ( ds < 1 )
+ ds = 1;
+
+ QRect rSlot;
+ if ( orientation() == Qt::Horizontal )
+ {
+ if ( innerRect.height() & 1 )
+ ws++;
+
+ rSlot = QRect( innerRect.x() + ds,
+ innerRect.y() + ( innerRect.height() - ws ) / 2,
+ innerRect.width() - 2 * ds, ws );
+ }
+ else
+ {
+ if ( innerRect.width() & 1 )
+ ws++;
+
+ rSlot = QRect( innerRect.x() + ( innerRect.width() - ws ) / 2,
+ innerRect.y() + ds,
+ ws, innerRect.height() - 2 * ds );
+ }
+
+ QBrush brush = palette().brush( QPalette::Dark );
+ qDrawShadePanel( painter, rSlot, palette(), true, 1 , &brush );
+ }
+
+ if ( isValid() )
+ drawHandle( painter, innerRect, transform( value() ) );
+}
+
+/*!
+ Draw the thumb at a position
+
+ \param painter Painter
+ \param sliderRect Bounding rectangle of the slider
+ \param pos Position of the slider thumb
+*/
+void QwtSlider::drawHandle( QPainter *painter,
+ const QRect &sliderRect, int pos ) const
+{
+ const int bw = d_data->borderWidth;
+
+ pos++; // shade line points one pixel below
+ if ( orientation() == Qt::Horizontal )
+ {
+ QRect handleRect(
+ pos - d_data->handleSize.width() / 2,
+ sliderRect.y(),
+ d_data->handleSize.width(),
+ sliderRect.height()
+ );
+
+ qDrawShadePanel( painter,
+ handleRect, palette(), false, bw,
+ &palette().brush( QPalette::Button ) );
+
+ qDrawShadeLine( painter, pos, sliderRect.top() + bw,
+ pos, sliderRect.bottom() - bw,
+ palette(), true, 1 );
+ }
+ else // Vertical
+ {
+ QRect handleRect(
+ sliderRect.left(),
+ pos - d_data->handleSize.height() / 2,
+ sliderRect.width(),
+ d_data->handleSize.height()
+ );
+
+ qDrawShadePanel( painter,
+ handleRect, palette(), false, bw,
+ &palette().brush( QPalette::Button ) );
+
+ qDrawShadeLine( painter, sliderRect.left() + bw, pos,
+ sliderRect.right() - bw, pos,
+ palette(), true, 1 );
+ }
+}
+
+/*!
+ Map and round a value into widget coordinates
+ \param value Value
+*/
+int QwtSlider::transform( double value ) const
+{
+ return qRound( d_data->map.transform( value ) );
+}
+
+/*!
+ Determine the value corresponding to a specified mouse location.
+ \param pos Mouse position
+*/
+double QwtSlider::getValue( const QPoint &pos )
+{
+ return d_data->map.invTransform(
+ orientation() == Qt::Horizontal ? pos.x() : pos.y() );
+}
+
+/*!
+ \brief Determine scrolling mode and direction
+ \param p point
+ \param scrollMode Scrolling mode
+ \param direction Direction
+*/
+void QwtSlider::getScrollMode( const QPoint &p,
+ QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const
+{
+ if ( !d_data->sliderRect.contains( p ) )
+ {
+ scrollMode = QwtAbstractSlider::ScrNone;
+ direction = 0;
+ return;
+ }
+
+ const int pos = ( orientation() == Qt::Horizontal ) ? p.x() : p.y();
+ const int markerPos = transform( value() );
+
+ if ( ( pos > markerPos - d_data->handleSize.width() / 2 )
+ && ( pos < markerPos + d_data->handleSize.width() / 2 ) )
+ {
+ scrollMode = QwtAbstractSlider::ScrMouse;
+ direction = 0;
+ return;
+ }
+
+ scrollMode = QwtAbstractSlider::ScrPage;
+ direction = ( pos > markerPos ) ? 1 : -1;
+
+ if ( scaleDraw()->scaleMap().p1() > scaleDraw()->scaleMap().p2() )
+ direction = -direction;
+}
+
+/*!
+ Qt paint event
+ \param event Paint event
+*/
+void QwtSlider::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->scalePos != QwtSlider::NoScale )
+ {
+ if ( !d_data->sliderRect.contains( event->rect() ) )
+ scaleDraw()->draw( &painter, palette() );
+ }
+
+ drawSlider( &painter, d_data->sliderRect );
+
+ if ( hasFocus() )
+ QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect );
+}
+
+//! Qt resize event
+void QwtSlider::resizeEvent( QResizeEvent * )
+{
+ layoutSlider( false );
+}
+
+//! Qt change event handler
+void QwtSlider::changeEvent( QEvent *event )
+{
+ switch( event->type() )
+ {
+ case QEvent::StyleChange:
+ case QEvent::FontChange:
+ layoutSlider( true );
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Recalculate the slider's geometry and layout based on
+ the current rect and fonts.
+ \param update_geometry notify the layout system and call update
+ to redraw the scale
+*/
+void QwtSlider::layoutSlider( bool update_geometry )
+{
+ int handleThickness;
+ if ( orientation() == Qt::Horizontal )
+ handleThickness = d_data->handleSize.width();
+ else
+ handleThickness = d_data->handleSize.height();
+
+ int sld1 = handleThickness / 2 - 1;
+ int sld2 = handleThickness / 2 + handleThickness % 2;
+
+ if ( d_data->bgStyle & QwtSlider::Trough )
+ {
+ sld1 += d_data->borderWidth;
+ sld2 += d_data->borderWidth;
+ }
+
+ int scd = 0;
+ if ( d_data->scalePos != QwtSlider::NoScale )
+ {
+ int d1, d2;
+ scaleDraw()->getBorderDistHint( font(), d1, d2 );
+ scd = qMax( d1, d2 );
+ }
+
+ int slo = scd - sld1;
+ if ( slo < 0 )
+ slo = 0;
+
+ int x, y, length;
+ QRect sliderRect;
+
+ length = x = y = 0;
+
+ const QRect cr = contentsRect();
+ if ( orientation() == Qt::Horizontal )
+ {
+ int sh = d_data->handleSize.height();
+ if ( d_data->bgStyle & QwtSlider::Trough )
+ sh += 2 * d_data->borderWidth;
+
+ sliderRect.setLeft( cr.left() + slo );
+ sliderRect.setRight( cr.right() - slo );
+ sliderRect.setTop( cr.top() );
+ sliderRect.setBottom( cr.top() + sh - 1);
+
+ if ( d_data->scalePos == QwtSlider::BottomScale )
+ {
+ y = sliderRect.bottom() + d_data->spacing;
+ }
+ else if ( d_data->scalePos == QwtSlider::TopScale )
+ {
+ sliderRect.setTop( cr.bottom() - sh + 1 );
+ sliderRect.setBottom( cr.bottom() );
+
+ y = sliderRect.top() - d_data->spacing;
+ }
+
+ x = sliderRect.left() + sld1;
+ length = sliderRect.width() - ( sld1 + sld2 );
+ }
+ else // Qt::Vertical
+ {
+ int sw = d_data->handleSize.width();
+ if ( d_data->bgStyle & QwtSlider::Trough )
+ sw += 2 * d_data->borderWidth;
+
+ sliderRect.setLeft( cr.right() - sw + 1 );
+ sliderRect.setRight( cr.right() );
+ sliderRect.setTop( cr.top() + slo );
+ sliderRect.setBottom( cr.bottom() - slo );
+
+ if ( d_data->scalePos == QwtSlider::LeftScale )
+ {
+ x = sliderRect.left() - d_data->spacing;
+ }
+ else if ( d_data->scalePos == QwtSlider::RightScale )
+ {
+ sliderRect.setLeft( cr.left() );
+ sliderRect.setRight( cr.left() + sw - 1);
+
+ x = sliderRect.right() + d_data->spacing;
+ }
+
+ y = sliderRect.top() + sld1;
+ length = sliderRect.height() - ( sld1 + sld2 );
+ }
+
+ d_data->sliderRect = sliderRect;
+
+ scaleDraw()->move( x, y );
+ scaleDraw()->setLength( length );
+
+ d_data->map.setPaintInterval( scaleDraw()->scaleMap().p1(),
+ scaleDraw()->scaleMap().p2() );
+
+ if ( update_geometry )
+ {
+ d_data->sizeHintCache = QSize(); // invalidate
+ updateGeometry();
+ update();
+ }
+}
+
+//! Notify change of value
+void QwtSlider::valueChange()
+{
+ QwtAbstractSlider::valueChange();
+ update();
+}
+
+
+//! Notify change of range
+void QwtSlider::rangeChange()
+{
+ d_data->map.setScaleInterval( minValue(), maxValue() );
+
+ if ( autoScale() )
+ rescale( minValue(), maxValue() );
+
+ QwtAbstractSlider::rangeChange();
+ layoutSlider( true );
+}
+
+/*!
+ Set the background style.
+*/
+void QwtSlider::setBackgroundStyle( BackgroundStyles style )
+{
+ d_data->bgStyle = style;
+ layoutSlider( true );
+}
+
+/*!
+ \return the background style.
+*/
+QwtSlider::BackgroundStyles QwtSlider::backgroundStyle() const
+{
+ return d_data->bgStyle;
+}
+
+/*!
+ \return QwtSlider::minimumSizeHint()
+*/
+QSize QwtSlider::sizeHint() const
+{
+ const QSize hint = minimumSizeHint();
+ return hint.expandedTo( QApplication::globalStrut() );
+}
+
+/*!
+ \brief Return a minimum size hint
+ \warning The return value of QwtSlider::minimumSizeHint() depends on
+ the font and the scale.
+*/
+QSize QwtSlider::minimumSizeHint() const
+{
+ if ( !d_data->sizeHintCache.isEmpty() )
+ return d_data->sizeHintCache;
+
+ const int minLength = 84; // from QSlider
+
+ int handleLength = d_data->handleSize.width();
+ int handleThickness = d_data->handleSize.height();
+
+ if ( orientation() == Qt::Vertical )
+ qSwap( handleLength, handleThickness );
+
+ int w = minLength;
+ int h = handleThickness;
+
+ if ( d_data->scalePos != QwtSlider::NoScale )
+ {
+ int d1, d2;
+ scaleDraw()->getBorderDistHint( font(), d1, d2 );
+
+ const int sdBorderDist = 2 * qMax( d1, d2 );
+ const int sdExtent = qCeil( scaleDraw()->extent( font() ) );
+ const int sdLength = scaleDraw()->minLength( font() );
+
+ int l = sdLength;
+ if ( handleLength > sdBorderDist )
+ {
+ // We need additional space for the overlapping handle
+ l += handleLength - sdBorderDist;
+ }
+
+ w = qMax( l, w );
+ h += sdExtent + d_data->spacing;
+ }
+
+ if ( d_data->bgStyle & QwtSlider::Trough )
+ h += 2 * d_data->borderWidth;
+
+ if ( orientation() == Qt::Vertical )
+ qSwap( w, h );
+
+ int left, right, top, bottom;
+ getContentsMargins( &left, &top, &right, &bottom );
+
+ w += left + right;
+ h += top + bottom;
+
+ d_data->sizeHintCache = QSize( w, h );
+ return d_data->sizeHintCache;
+}
diff --git a/src/libpcp_qwt/src/qwt_slider.h b/src/libpcp_qwt/src/qwt_slider.h
new file mode 100644
index 0000000..bc39456
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_slider.h
@@ -0,0 +1,150 @@
+/* -*- 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_SLIDER_H
+#define QWT_SLIDER_H
+
+#include "qwt_global.h"
+#include "qwt_abstract_scale.h"
+#include "qwt_abstract_slider.h"
+
+class QwtScaleDraw;
+
+/*!
+ \brief The Slider Widget
+
+ QwtSlider is a slider widget which operates on an interval
+ of type double. QwtSlider supports different layouts as
+ well as a scale.
+
+ \image html sliders.png
+
+ \sa QwtAbstractSlider and QwtAbstractScale for the descriptions
+ of the inherited members.
+*/
+
+class QWT_EXPORT QwtSlider : public QwtAbstractSlider, public QwtAbstractScale
+{
+ Q_OBJECT
+ Q_ENUMS( ScalePos )
+ Q_ENUMS( BackgroundStyle )
+ Q_PROPERTY( ScalePos scalePosition READ scalePosition
+ WRITE setScalePosition )
+ Q_PROPERTY( BackgroundStyles backgroundStyle
+ READ backgroundStyle WRITE setBackgroundStyle )
+ Q_PROPERTY( QSize handleSize READ handleSize WRITE setHandleSize )
+ Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
+ Q_PROPERTY( int spacing READ spacing WRITE setSpacing )
+
+public:
+
+ /*!
+ Scale position. QwtSlider tries to enforce valid combinations of its
+ orientation and scale position:
+
+ - Qt::Horizonal combines with NoScale, TopScale and BottomScale
+ - Qt::Vertical combines with NoScale, LeftScale and RightScale
+
+ \sa QwtSlider()
+ */
+ enum ScalePos
+ {
+ //! The slider has no scale
+ NoScale,
+
+ //! The scale is left of the slider
+ LeftScale,
+
+ //! The scale is right of the slider
+ RightScale,
+
+ //! The scale is above of the slider
+ TopScale,
+
+ //! The scale is below of the slider
+ BottomScale
+ };
+
+ /*!
+ Background style.
+ \sa QwtSlider()
+ */
+ enum BackgroundStyle
+ {
+ //! Trough background
+ Trough = 0x01,
+
+ //! Groove
+ Groove = 0x02,
+ };
+
+ //! Background styles
+ typedef QFlags<BackgroundStyle> BackgroundStyles;
+
+ explicit QwtSlider( QWidget *parent,
+ Qt::Orientation = Qt::Horizontal,
+ ScalePos = NoScale, BackgroundStyles = Trough );
+
+ virtual ~QwtSlider();
+
+ virtual void setOrientation( Qt::Orientation );
+
+ void setBackgroundStyle( BackgroundStyles );
+ BackgroundStyles backgroundStyle() const;
+
+ void setScalePosition( ScalePos s );
+ ScalePos scalePosition() const;
+
+ void setHandleSize( int width, int height );
+ void setHandleSize( const QSize & );
+ QSize handleSize() const;
+
+ void setBorderWidth( int bw );
+ int borderWidth() const;
+
+ void setSpacing( int );
+ int spacing() const;
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ void setScaleDraw( QwtScaleDraw * );
+ const QwtScaleDraw *scaleDraw() const;
+
+protected:
+ virtual double getValue( const QPoint &p );
+ virtual void getScrollMode( const QPoint &p,
+ QwtAbstractSlider::ScrollMode &, int &direction ) const;
+
+ virtual void drawSlider ( QPainter *, const QRect & ) const;
+ virtual void drawHandle( QPainter *, const QRect &, int pos ) const;
+
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void paintEvent ( QPaintEvent * );
+ virtual void changeEvent( QEvent * );
+
+ virtual void valueChange();
+ virtual void rangeChange();
+ virtual void scaleChange();
+
+ int transform( double v ) const;
+
+ QwtScaleDraw *scaleDraw();
+
+private:
+ void layoutSlider( bool );
+ void initSlider( Qt::Orientation, ScalePos, BackgroundStyles );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtSlider::BackgroundStyles )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_spline.cpp b/src/libpcp_qwt/src/qwt_spline.cpp
new file mode 100644
index 0000000..5c1e13f
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_spline.cpp
@@ -0,0 +1,380 @@
+/* -*- 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_spline.h"
+#include "qwt_math.h"
+
+class QwtSpline::PrivateData
+{
+public:
+ PrivateData():
+ splineType( QwtSpline::Natural )
+ {
+ }
+
+ QwtSpline::SplineType splineType;
+
+ // coefficient vectors
+ QVector<double> a;
+ QVector<double> b;
+ QVector<double> c;
+
+ // control points
+ QPolygonF points;
+};
+
+static int lookup( double x, const QPolygonF &values )
+{
+#if 0
+//qLowerBound/qHigherBound ???
+#endif
+ int i1;
+ const int size = values.size();
+
+ if ( x <= values[0].x() )
+ i1 = 0;
+ else if ( x >= values[size - 2].x() )
+ i1 = size - 2;
+ else
+ {
+ i1 = 0;
+ int i2 = size - 2;
+ int i3 = 0;
+
+ while ( i2 - i1 > 1 )
+ {
+ i3 = i1 + ( ( i2 - i1 ) >> 1 );
+
+ if ( values[i3].x() > x )
+ i2 = i3;
+ else
+ i1 = i3;
+ }
+ }
+ return i1;
+}
+
+//! Constructor
+QwtSpline::QwtSpline()
+{
+ d_data = new PrivateData;
+}
+
+/*!
+ Copy constructor
+ \param other Spline used for initilization
+*/
+QwtSpline::QwtSpline( const QwtSpline& other )
+{
+ d_data = new PrivateData( *other.d_data );
+}
+
+/*!
+ Assignment operator
+ \param other Spline used for initilization
+*/
+QwtSpline &QwtSpline::operator=( const QwtSpline & other )
+{
+ *d_data = *other.d_data;
+ return *this;
+}
+
+//! Destructor
+QwtSpline::~QwtSpline()
+{
+ delete d_data;
+}
+
+/*!
+ Select the algorithm used for calculating the spline
+
+ \param splineType Spline type
+ \sa splineType()
+*/
+void QwtSpline::setSplineType( SplineType splineType )
+{
+ d_data->splineType = splineType;
+}
+
+/*!
+ \return the spline type
+ \sa setSplineType()
+*/
+QwtSpline::SplineType QwtSpline::splineType() const
+{
+ return d_data->splineType;
+}
+
+/*!
+ \brief Calculate the spline coefficients
+
+ Depending on the value of \a periodic, this function
+ will determine the coefficients for a natural or a periodic
+ spline and store them internally.
+
+ \param points Points
+ \return true if successful
+ \warning The sequence of x (but not y) values has to be strictly monotone
+ increasing, which means <code>points[i].x() < points[i+1].x()</code>.
+ If this is not the case, the function will return false
+*/
+bool QwtSpline::setPoints( const QPolygonF& points )
+{
+ const int size = points.size();
+ if ( size <= 2 )
+ {
+ reset();
+ return false;
+ }
+
+ d_data->points = points;
+
+ d_data->a.resize( size - 1 );
+ d_data->b.resize( size - 1 );
+ d_data->c.resize( size - 1 );
+
+ bool ok;
+ if ( d_data->splineType == Periodic )
+ ok = buildPeriodicSpline( points );
+ else
+ ok = buildNaturalSpline( points );
+
+ if ( !ok )
+ reset();
+
+ return ok;
+}
+
+/*!
+ Return points passed by setPoints
+*/
+QPolygonF QwtSpline::points() const
+{
+ return d_data->points;
+}
+
+//! \return A coefficients
+const QVector<double> &QwtSpline::coefficientsA() const
+{
+ return d_data->a;
+}
+
+//! \return B coefficients
+const QVector<double> &QwtSpline::coefficientsB() const
+{
+ return d_data->b;
+}
+
+//! \return C coefficients
+const QVector<double> &QwtSpline::coefficientsC() const
+{
+ return d_data->c;
+}
+
+
+//! Free allocated memory and set size to 0
+void QwtSpline::reset()
+{
+ d_data->a.resize( 0 );
+ d_data->b.resize( 0 );
+ d_data->c.resize( 0 );
+ d_data->points.resize( 0 );
+}
+
+//! True if valid
+bool QwtSpline::isValid() const
+{
+ return d_data->a.size() > 0;
+}
+
+/*!
+ Calculate the interpolated function value corresponding
+ to a given argument x.
+*/
+double QwtSpline::value( double x ) const
+{
+ if ( d_data->a.size() == 0 )
+ return 0.0;
+
+ const int i = lookup( x, d_data->points );
+
+ const double delta = x - d_data->points[i].x();
+ return( ( ( ( d_data->a[i] * delta ) + d_data->b[i] )
+ * delta + d_data->c[i] ) * delta + d_data->points[i].y() );
+}
+
+/*!
+ \brief Determines the coefficients for a natural spline
+ \return true if successful
+*/
+bool QwtSpline::buildNaturalSpline( const QPolygonF &points )
+{
+ int i;
+
+ const QPointF *p = points.data();
+ const int size = points.size();
+
+ double *a = d_data->a.data();
+ double *b = d_data->b.data();
+ double *c = d_data->c.data();
+
+ // set up tridiagonal equation system; use coefficient
+ // vectors as temporary buffers
+ QVector<double> h( size - 1 );
+ for ( i = 0; i < size - 1; i++ )
+ {
+ h[i] = p[i+1].x() - p[i].x();
+ if ( h[i] <= 0 )
+ return false;
+ }
+
+ QVector<double> d( size - 1 );
+ double dy1 = ( p[1].y() - p[0].y() ) / h[0];
+ for ( i = 1; i < size - 1; i++ )
+ {
+ b[i] = c[i] = h[i];
+ a[i] = 2.0 * ( h[i-1] + h[i] );
+
+ const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i];
+ d[i] = 6.0 * ( dy1 - dy2 );
+ dy1 = dy2;
+ }
+
+ //
+ // solve it
+ //
+
+ // L-U Factorization
+ for ( i = 1; i < size - 2; i++ )
+ {
+ c[i] /= a[i];
+ a[i+1] -= b[i] * c[i];
+ }
+
+ // forward elimination
+ QVector<double> s( size );
+ s[1] = d[1];
+ for ( i = 2; i < size - 1; i++ )
+ s[i] = d[i] - c[i-1] * s[i-1];
+
+ // backward elimination
+ s[size - 2] = - s[size - 2] / a[size - 2];
+ for ( i = size - 3; i > 0; i-- )
+ s[i] = - ( s[i] + b[i] * s[i+1] ) / a[i];
+ s[size - 1] = s[0] = 0.0;
+
+ //
+ // Finally, determine the spline coefficients
+ //
+ for ( i = 0; i < size - 1; i++ )
+ {
+ a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] );
+ b[i] = 0.5 * s[i];
+ c[i] = ( p[i+1].y() - p[i].y() ) / h[i]
+ - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
+ }
+
+ return true;
+}
+
+/*!
+ \brief Determines the coefficients for a periodic spline
+ \return true if successful
+*/
+bool QwtSpline::buildPeriodicSpline( const QPolygonF &points )
+{
+ int i;
+
+ const QPointF *p = points.data();
+ const int size = points.size();
+
+ double *a = d_data->a.data();
+ double *b = d_data->b.data();
+ double *c = d_data->c.data();
+
+ QVector<double> d( size - 1 );
+ QVector<double> h( size - 1 );
+ QVector<double> s( size );
+
+ //
+ // setup equation system; use coefficient
+ // vectors as temporary buffers
+ //
+ for ( i = 0; i < size - 1; i++ )
+ {
+ h[i] = p[i+1].x() - p[i].x();
+ if ( h[i] <= 0.0 )
+ return false;
+ }
+
+ const int imax = size - 2;
+ double htmp = h[imax];
+ double dy1 = ( p[0].y() - p[imax].y() ) / htmp;
+ for ( i = 0; i <= imax; i++ )
+ {
+ b[i] = c[i] = h[i];
+ a[i] = 2.0 * ( htmp + h[i] );
+ const double dy2 = ( p[i+1].y() - p[i].y() ) / h[i];
+ d[i] = 6.0 * ( dy1 - dy2 );
+ dy1 = dy2;
+ htmp = h[i];
+ }
+
+ //
+ // solve it
+ //
+
+ // L-U Factorization
+ a[0] = qSqrt( a[0] );
+ c[0] = h[imax] / a[0];
+ double sum = 0;
+
+ for ( i = 0; i < imax - 1; i++ )
+ {
+ b[i] /= a[i];
+ if ( i > 0 )
+ c[i] = - c[i-1] * b[i-1] / a[i];
+ a[i+1] = qSqrt( a[i+1] - qwtSqr( b[i] ) );
+ sum += qwtSqr( c[i] );
+ }
+ b[imax-1] = ( b[imax-1] - c[imax-2] * b[imax-2] ) / a[imax-1];
+ a[imax] = qSqrt( a[imax] - qwtSqr( b[imax-1] ) - sum );
+
+
+ // forward elimination
+ s[0] = d[0] / a[0];
+ sum = 0;
+ for ( i = 1; i < imax; i++ )
+ {
+ s[i] = ( d[i] - b[i-1] * s[i-1] ) / a[i];
+ sum += c[i-1] * s[i-1];
+ }
+ s[imax] = ( d[imax] - b[imax-1] * s[imax-1] - sum ) / a[imax];
+
+
+ // backward elimination
+ s[imax] = - s[imax] / a[imax];
+ s[imax-1] = -( s[imax-1] + b[imax-1] * s[imax] ) / a[imax-1];
+ for ( i = imax - 2; i >= 0; i-- )
+ s[i] = - ( s[i] + b[i] * s[i+1] + c[i] * s[imax] ) / a[i];
+
+ //
+ // Finally, determine the spline coefficients
+ //
+ s[size-1] = s[0];
+ for ( i = 0; i < size - 1; i++ )
+ {
+ a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i] );
+ b[i] = 0.5 * s[i];
+ c[i] = ( p[i+1].y() - p[i].y() )
+ / h[i] - ( s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
+ }
+
+ return true;
+}
diff --git a/src/libpcp_qwt/src/qwt_spline.h b/src/libpcp_qwt/src/qwt_spline.h
new file mode 100644
index 0000000..802e1da
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_spline.h
@@ -0,0 +1,101 @@
+/* -*- 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_SPLINE_H
+#define QWT_SPLINE_H
+
+#include "qwt_global.h"
+#include <qpolygon.h>
+#include <qvector.h>
+
+/*!
+ \brief A class for spline interpolation
+
+ The QwtSpline class is used for cubical spline interpolation.
+ Two types of splines, natural and periodic, are supported.
+
+ \par Usage:
+ <ol>
+ <li>First call setPoints() to determine the spline coefficients
+ for a tabulated function y(x).
+ <li>After the coefficients have been set up, the interpolated
+ function value for an argument x can be determined by calling
+ QwtSpline::value().
+ </ol>
+
+ \par Example:
+ \code
+#include <qwt_spline.h>
+
+QPolygonF interpolate(const QPolygonF& points, int numValues)
+{
+ QwtSpline spline;
+ if ( !spline.setPoints(points) )
+ return points;
+
+ QPolygonF interpolatedPoints(numValues);
+
+ const double delta =
+ (points[numPoints - 1].x() - points[0].x()) / (points.size() - 1);
+ for(i = 0; i < points.size(); i++) / interpolate
+ {
+ const double x = points[0].x() + i * delta;
+ interpolatedPoints[i].setX(x);
+ interpolatedPoints[i].setY(spline.value(x));
+ }
+ return interpolatedPoints;
+}
+ \endcode
+*/
+
+class QWT_EXPORT QwtSpline
+{
+public:
+ //! Spline type
+ enum SplineType
+ {
+ //! A natural spline
+ Natural,
+
+ //! A periodic spline
+ Periodic
+ };
+
+ QwtSpline();
+ QwtSpline( const QwtSpline & );
+
+ ~QwtSpline();
+
+ QwtSpline &operator=( const QwtSpline & );
+
+ void setSplineType( SplineType );
+ SplineType splineType() const;
+
+ bool setPoints( const QPolygonF& points );
+ QPolygonF points() const;
+
+ void reset();
+
+ bool isValid() const;
+ double value( double x ) const;
+
+ const QVector<double> &coefficientsA() const;
+ const QVector<double> &coefficientsB() const;
+ const QVector<double> &coefficientsC() const;
+
+protected:
+ bool buildNaturalSpline( const QPolygonF & );
+ bool buildPeriodicSpline( const QPolygonF & );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_symbol.cpp b/src/libpcp_qwt/src/qwt_symbol.cpp
new file mode 100644
index 0000000..0966814
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_symbol.cpp
@@ -0,0 +1,1006 @@
+/* -*- 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_symbol.h"
+#include "qwt_painter.h"
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qmath.h>
+
+namespace QwtTriangle
+{
+ enum Type
+ {
+ Left,
+ Right,
+ Up,
+ Down
+ };
+}
+
+static inline void qwtDrawEllipseSymbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ painter->setBrush( symbol.brush() );
+ painter->setPen( symbol.pen() );
+
+ const QSize size = symbol.size();
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ const int sw = size.width();
+ const int sh = size.height();
+ const int sw2 = size.width() / 2;
+ const int sh2 = size.height() / 2;
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const int x = qRound( points[i].x() );
+ const int y = qRound( points[i].y() );
+
+ const QRectF r( x - sw2, y - sh2, sw, sh );
+ QwtPainter::drawEllipse( painter, r );
+ }
+ }
+ else
+ {
+ const double sw = size.width();
+ const double sh = size.height();
+ const double sw2 = 0.5 * size.width();
+ const double sh2 = 0.5 * size.height();
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const double x = points[i].x();
+ const double y = points[i].y();
+
+ const QRectF r( x - sw2, y - sh2, sw, sh );
+ QwtPainter::drawEllipse( painter, r );
+ }
+ }
+}
+
+static inline void qwtDrawRectSymbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+
+ QPen pen = symbol.pen();
+ pen.setJoinStyle( Qt::MiterJoin );
+ painter->setPen( pen );
+ painter->setBrush( symbol.brush() );
+ painter->setRenderHint( QPainter::Antialiasing, false );
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ const int sw = size.width();
+ const int sh = size.height();
+ const int sw2 = size.width() / 2;
+ const int sh2 = size.height() / 2;
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const int x = qRound( points[i].x() );
+ const int y = qRound( points[i].y() );
+
+ const QRect r( x - sw2, y - sh2, sw, sh );
+ QwtPainter::drawRect( painter, r );
+ }
+ }
+ else
+ {
+ const double sw = size.width();
+ const double sh = size.height();
+ const double sw2 = 0.5 * size.width();
+ const double sh2 = 0.5 * size.height();
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const double x = points[i].x();
+ const double y = points[i].y();
+
+ const QRectF r( x - sw2, y - sh2, sw, sh );
+ QwtPainter::drawRect( painter, r );
+ }
+ }
+}
+
+static inline void qwtDrawDiamondSymbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+
+ QPen pen = symbol.pen();
+ pen.setJoinStyle( Qt::MiterJoin );
+ painter->setPen( pen );
+ painter->setBrush( symbol.brush() );
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const int x = qRound( points[i].x() );
+ const int y = qRound( points[i].y() );
+
+ const int x1 = x - size.width() / 2;
+ const int y1 = y - size.height() / 2;
+ const int x2 = x1 + size.width();
+ const int y2 = y1 + size.height();
+
+ QPolygonF polygon;
+ polygon += QPointF( x, y1 );
+ polygon += QPointF( x1, y );
+ polygon += QPointF( x, y2 );
+ polygon += QPointF( x2, y );
+
+ QwtPainter::drawPolygon( painter, polygon );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const QPointF &pos = points[i];
+
+ const double x1 = pos.x() - 0.5 * size.width();
+ const double y1 = pos.y() - 0.5 * size.height();
+ const double x2 = x1 + size.width();
+ const double y2 = y1 + size.height();
+
+ QPolygonF polygon;
+ polygon += QPointF( pos.x(), y1 );
+ polygon += QPointF( x2, pos.y() );
+ polygon += QPointF( pos.x(), y2 );
+ polygon += QPointF( x1, pos.y() );
+
+ QwtPainter::drawPolygon( painter, polygon );
+ }
+ }
+}
+
+static inline void qwtDrawTriangleSymbols(
+ QPainter *painter, QwtTriangle::Type type,
+ const QPointF *points, int numPoints,
+ const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+
+ QPen pen = symbol.pen();
+ pen.setJoinStyle( Qt::MiterJoin );
+ painter->setPen( pen );
+
+ painter->setBrush( symbol.brush() );
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ double sw2 = 0.5 * size.width();
+ double sh2 = 0.5 * size.height();
+
+ if ( doAlign )
+ {
+ sw2 = qFloor( sw2 );
+ sh2 = qFloor( sh2 );
+ }
+
+ QPolygonF triangle( 3 );
+ QPointF *trianglePoints = triangle.data();
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const QPointF &pos = points[i];
+
+ double x = pos.x();
+ double y = pos.y();
+
+ if ( doAlign )
+ {
+ x = qRound( x );
+ y = qRound( y );
+ }
+
+ const double x1 = x - sw2;
+ const double x2 = x1 + size.width();
+ const double y1 = y - sh2;
+ const double y2 = y1 + size.height();
+
+ switch ( type )
+ {
+ case QwtTriangle::Left:
+ {
+ trianglePoints[0].rx() = x2;
+ trianglePoints[0].ry() = y1;
+
+ trianglePoints[1].rx() = x1;
+ trianglePoints[1].ry() = y;
+
+ trianglePoints[2].rx() = x2;
+ trianglePoints[2].ry() = y2;
+
+ break;
+ }
+ case QwtTriangle::Right:
+ {
+ trianglePoints[0].rx() = x1;
+ trianglePoints[0].ry() = y1;
+
+ trianglePoints[1].rx() = x2;
+ trianglePoints[1].ry() = y;
+
+ trianglePoints[2].rx() = x1;
+ trianglePoints[2].ry() = y2;
+
+ break;
+ }
+ case QwtTriangle::Up:
+ {
+ trianglePoints[0].rx() = x1;
+ trianglePoints[0].ry() = y2;
+
+ trianglePoints[1].rx() = x;
+ trianglePoints[1].ry() = y1;
+
+ trianglePoints[2].rx() = x2;
+ trianglePoints[2].ry() = y2;
+
+ break;
+ }
+ case QwtTriangle::Down:
+ {
+ trianglePoints[0].rx() = x1;
+ trianglePoints[0].ry() = y1;
+
+ trianglePoints[1].rx() = x;
+ trianglePoints[1].ry() = y2;
+
+ trianglePoints[2].rx() = x2;
+ trianglePoints[2].ry() = y1;
+
+ break;
+ }
+ }
+ QwtPainter::drawPolygon( painter, triangle );
+ }
+}
+
+static inline void qwtDrawLineSymbols(
+ QPainter *painter, int orientations,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+
+ int off = 0;
+
+ QPen pen = symbol.pen();
+ if ( pen.width() > 1 )
+ {
+ pen.setCapStyle( Qt::FlatCap );
+ off = 1;
+ }
+
+ painter->setPen( pen );
+ painter->setRenderHint( QPainter::Antialiasing, false );
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ const int sw = qFloor( size.width() );
+ const int sh = qFloor( size.height() );
+ const int sw2 = size.width() / 2;
+ const int sh2 = size.height() / 2;
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ if ( orientations & Qt::Horizontal )
+ {
+ const int x = qRound( points[i].x() ) - sw2;
+ const int y = qRound( points[i].y() );
+
+ QwtPainter::drawLine( painter, x, y, x + sw + off, y );
+ }
+ if ( orientations & Qt::Vertical )
+ {
+ const int x = qRound( points[i].x() );
+ const int y = qRound( points[i].y() ) - sh2;
+
+ QwtPainter::drawLine( painter, x, y, x, y + sh + off );
+ }
+ }
+ }
+ else
+ {
+ const double sw = size.width();
+ const double sh = size.height();
+ const double sw2 = 0.5 * size.width();
+ const double sh2 = 0.5 * size.height();
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ if ( orientations & Qt::Horizontal )
+ {
+ const double x = points[i].x() - sw2;
+ const double y = points[i].y();
+
+ QwtPainter::drawLine( painter, x, y, x + sw, y );
+ }
+ if ( orientations & Qt::Vertical )
+ {
+ const double y = points[i].y() - sh2;
+ const double x = points[i].x();
+
+ QwtPainter::drawLine( painter, x, y, x, y + sh );
+ }
+ }
+ }
+}
+
+static inline void qwtDrawXCrossSymbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+ int off = 0;
+
+ QPen pen = symbol.pen();
+ if ( pen.width() > 1 )
+ {
+ pen.setCapStyle( Qt::FlatCap );
+ off = 1;
+ }
+ painter->setPen( pen );
+
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ const int sw = size.width();
+ const int sh = size.height();
+ const int sw2 = size.width() / 2;
+ const int sh2 = size.height() / 2;
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const QPointF &pos = points[i];
+
+ const int x = qRound( pos.x() );
+ const int y = qRound( pos.y() );
+
+ const int x1 = x - sw2;
+ const int x2 = x1 + sw + off;
+ const int y1 = y - sh2;
+ const int y2 = y1 + sh + off;
+
+ QwtPainter::drawLine( painter, x1, y1, x2, y2 );
+ QwtPainter::drawLine( painter, x2, y1, x1, y2 );
+ }
+ }
+ else
+ {
+ const double sw = size.width();
+ const double sh = size.height();
+ const double sw2 = 0.5 * size.width();
+ const double sh2 = 0.5 * size.height();
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ const QPointF &pos = points[i];
+
+ const double x1 = pos.x() - sw2;
+ const double x2 = x1 + sw;
+ const double y1 = pos.y() - sh2;
+ const double y2 = y1 + sh;
+
+ QwtPainter::drawLine( painter, x1, y1, x2, y2 );
+ QwtPainter::drawLine( painter, x1, y2, x2, y1 );
+ }
+ }
+}
+
+static inline void qwtDrawStar1Symbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ const QSize size = symbol.size();
+ painter->setPen( symbol.pen() );
+
+ if ( QwtPainter::roundingAlignment( painter ) )
+ {
+ QRect r( 0, 0, size.width(), size.height() );
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ r.moveCenter( points[i].toPoint() );
+
+ const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
+
+ const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
+
+ QwtPainter::drawLine( painter,
+ qRound( r.left() + d1 ), qRound( r.top() + d1 ),
+ qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) );
+ QwtPainter::drawLine( painter,
+ qRound( r.left() + d1 ), qRound( r.bottom() - d1 ),
+ qRound( r .right() - d1), qRound( r.top() + d1 ) );
+
+ const QPoint c = r.center();
+
+ QwtPainter::drawLine( painter,
+ c.x(), r.top(), c.x(), r.bottom() );
+ QwtPainter::drawLine( painter,
+ r.left(), c.y(), r.right(), c.y() );
+ }
+ }
+ else
+ {
+ QRectF r( 0, 0, size.width(), size.height() );
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ r.moveCenter( points[i] );
+
+ const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
+
+ const QPointF c = r.center();
+ const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
+
+ QwtPainter::drawLine( painter,
+ r.left() + d1, r.top() + d1,
+ r.right() - d1, r.bottom() - d1 );
+ QwtPainter::drawLine( painter,
+ r.left() + d1, r.bottom() - d1,
+ r.right() - d1, r.top() + d1 );
+ QwtPainter::drawLine( painter,
+ c.x(), r.top(),
+ c.x(), r.bottom() );
+ QwtPainter::drawLine( painter,
+ r.left(), c.y(),
+ r.right(), c.y() );
+ }
+ }
+}
+
+static inline void qwtDrawStar2Symbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ QPen pen = symbol.pen();
+ if ( pen.width() > 1 )
+ pen.setCapStyle( Qt::FlatCap );
+ pen.setJoinStyle( Qt::MiterJoin );
+ painter->setPen( pen );
+
+ painter->setBrush( symbol.brush() );
+
+ const double cos30 = 0.866025; // cos(30°)
+
+ const double dy = 0.25 * symbol.size().height();
+ const double dx = 0.5 * symbol.size().width() * cos30 / 3.0;
+
+ QPolygonF star( 12 );
+ QPointF *starPoints = star.data();
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ double x = points[i].x();
+ double y = points[i].y();
+ if ( doAlign )
+ {
+ x = qRound( x );
+ y = qRound( y );
+ }
+
+ double x1 = x - 3 * dx;
+ double y1 = y - 2 * dy;
+ if ( doAlign )
+ {
+ x1 = qRound( x - 3 * dx );
+ y1 = qRound( y - 2 * dy );
+ }
+
+ const double x2 = x1 + 1 * dx;
+ const double x3 = x1 + 2 * dx;
+ const double x4 = x1 + 3 * dx;
+ const double x5 = x1 + 4 * dx;
+ const double x6 = x1 + 5 * dx;
+ const double x7 = x1 + 6 * dx;
+
+ const double y2 = y1 + 1 * dy;
+ const double y3 = y1 + 2 * dy;
+ const double y4 = y1 + 3 * dy;
+ const double y5 = y1 + 4 * dy;
+
+ starPoints[0].rx() = x4;
+ starPoints[0].ry() = y1;
+
+ starPoints[1].rx() = x5;
+ starPoints[1].ry() = y2;
+
+ starPoints[2].rx() = x7;
+ starPoints[2].ry() = y2;
+
+ starPoints[3].rx() = x6;
+ starPoints[3].ry() = y3;
+
+ starPoints[4].rx() = x7;
+ starPoints[4].ry() = y4;
+
+ starPoints[5].rx() = x5;
+ starPoints[5].ry() = y4;
+
+ starPoints[6].rx() = x4;
+ starPoints[6].ry() = y5;
+
+ starPoints[7].rx() = x3;
+ starPoints[7].ry() = y4;
+
+ starPoints[8].rx() = x1;
+ starPoints[8].ry() = y4;
+
+ starPoints[9].rx() = x2;
+ starPoints[9].ry() = y3;
+
+ starPoints[10].rx() = x1;
+ starPoints[10].ry() = y2;
+
+ starPoints[11].rx() = x3;
+ starPoints[11].ry() = y2;
+
+ QwtPainter::drawPolygon( painter, star );
+ }
+}
+
+static inline void qwtDrawHexagonSymbols( QPainter *painter,
+ const QPointF *points, int numPoints, const QwtSymbol &symbol )
+{
+ painter->setBrush( symbol.brush() );
+ painter->setPen( symbol.pen() );
+
+ const double cos30 = 0.866025; // cos(30°)
+ const double dx = 0.5 * ( symbol.size().width() - cos30 );
+
+ const double dy = 0.25 * symbol.size().height();
+
+ QPolygonF hexaPolygon( 6 );
+ QPointF *hexaPoints = hexaPolygon.data();
+
+ const bool doAlign = QwtPainter::roundingAlignment( painter );
+
+ for ( int i = 0; i < numPoints; i++ )
+ {
+ double x = points[i].x();
+ double y = points[i].y();
+ if ( doAlign )
+ {
+ x = qRound( x );
+ y = qRound( y );
+ }
+
+ double x1 = x - dx;
+ double y1 = y - 2 * dy;
+ if ( doAlign )
+ {
+ x1 = qCeil( x1 );
+ y1 = qCeil( y1 );
+ }
+
+ const double x2 = x1 + 1 * dx;
+ const double x3 = x1 + 2 * dx;
+
+ const double y2 = y1 + 1 * dy;
+ const double y3 = y1 + 3 * dy;
+ const double y4 = y1 + 4 * dy;
+
+ hexaPoints[0].rx() = x2;
+ hexaPoints[0].ry() = y1;
+
+ hexaPoints[1].rx() = x3;
+ hexaPoints[1].ry() = y2;
+
+ hexaPoints[2].rx() = x3;
+ hexaPoints[2].ry() = y3;
+
+ hexaPoints[3].rx() = x2;
+ hexaPoints[3].ry() = y4;
+
+ hexaPoints[4].rx() = x1;
+ hexaPoints[4].ry() = y3;
+
+ hexaPoints[5].rx() = x1;
+ hexaPoints[5].ry() = y2;
+
+ QwtPainter::drawPolygon( painter, hexaPolygon );
+ }
+}
+
+class QwtSymbol::PrivateData
+{
+public:
+ PrivateData( QwtSymbol::Style st, const QBrush &br,
+ const QPen &pn, const QSize &sz ):
+ style( st ),
+ size( sz ),
+ brush( br ),
+ pen( pn )
+ {
+ }
+
+ bool operator==( const PrivateData &other ) const
+ {
+ return ( style == other.style )
+ && ( size == other.size )
+ && ( brush == other.brush )
+ && ( pen == other.pen );
+ }
+
+
+ Style style;
+ QSize size;
+ QBrush brush;
+ QPen pen;
+};
+
+/*!
+ Default Constructor
+ \param style Symbol Style
+
+ The symbol is constructed with gray interior,
+ black outline with zero width, no size and style 'NoSymbol'.
+*/
+QwtSymbol::QwtSymbol( Style style )
+{
+ d_data = new PrivateData( style, QBrush( Qt::gray ),
+ QPen( Qt::black ), QSize( 0.0, 0.0 ) );
+}
+
+/*!
+ \brief Constructor
+ \param style Symbol Style
+ \param brush brush to fill the interior
+ \param pen outline pen
+ \param size size
+
+ \sa setStyle(), setBrush(), setPen(), setSize()
+*/
+QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush &brush,
+ const QPen &pen, const QSize &size )
+{
+ d_data = new PrivateData( style, brush, pen, size );
+}
+
+/*!
+ \brief Copy constructor
+
+ \param other Symbol
+*/
+QwtSymbol::QwtSymbol( const QwtSymbol &other )
+{
+ d_data = new PrivateData( other.style(), other.brush(),
+ other.pen(), other.size() );
+};
+
+//! Destructor
+QwtSymbol::~QwtSymbol()
+{
+ delete d_data;
+}
+
+//! \brief Assignment operator
+QwtSymbol &QwtSymbol::operator=( const QwtSymbol &other )
+{
+ *d_data = *other.d_data;
+ return *this;
+}
+
+//! \brief Compare two symbols
+bool QwtSymbol::operator==( const QwtSymbol &other ) const
+{
+ return *d_data == *other.d_data;
+}
+
+//! \brief Compare two symbols
+bool QwtSymbol::operator!=( const QwtSymbol &other ) const
+{
+ return !( *d_data == *other.d_data );
+}
+
+/*!
+ \brief Specify the symbol's size
+
+ If the 'h' parameter is left out or less than 0,
+ and the 'w' parameter is greater than or equal to 0,
+ the symbol size will be set to (w,w).
+ \param width Width
+ \param height Height (defaults to -1)
+
+ \sa size()
+*/
+void QwtSymbol::setSize( int width, int height )
+{
+ if ( ( width >= 0 ) && ( height < 0 ) )
+ height = width;
+
+ d_data->size = QSize( width, height );
+}
+
+/*!
+ Set the symbol's size
+ \param size Size
+
+ \sa size()
+*/
+void QwtSymbol::setSize( const QSize &size )
+{
+ if ( size.isValid() )
+ d_data->size = size;
+}
+
+/*!
+ \return Size
+ \sa setSize()
+*/
+const QSize& QwtSymbol::size() const
+{
+ return d_data->size;
+}
+
+/*!
+ \brief Assign a brush
+
+ The brush is used to draw the interior of the symbol.
+ \param brush Brush
+
+ \sa brush()
+*/
+void QwtSymbol::setBrush( const QBrush &brush )
+{
+ d_data->brush = brush;
+}
+
+/*!
+ \return Brush
+ \sa setBrush()
+*/
+const QBrush& QwtSymbol::brush() const
+{
+ return d_data->brush;
+}
+
+/*!
+ Assign a pen
+
+ The pen is used to draw the symbol's outline.
+
+ \param pen Pen
+ \sa pen(), setBrush()
+*/
+void QwtSymbol::setPen( const QPen &pen )
+{
+ d_data->pen = pen;
+}
+
+/*!
+ \return Pen
+ \sa setPen(), brush()
+*/
+const QPen& QwtSymbol::pen() const
+{
+ return d_data->pen;
+}
+
+/*!
+ \brief Set the color of the symbol
+
+ Change the color of the brush for symbol types with a filled area.
+ For all other symbol types the color will be assigned to the pen.
+
+ \param color Color
+
+ \sa setBrush(), setPen(), brush(), pen()
+*/
+void QwtSymbol::setColor( const QColor &color )
+{
+ switch ( d_data->style )
+ {
+ case QwtSymbol::Ellipse:
+ case QwtSymbol::Rect:
+ case QwtSymbol::Diamond:
+ case QwtSymbol::Triangle:
+ case QwtSymbol::UTriangle:
+ case QwtSymbol::DTriangle:
+ case QwtSymbol::RTriangle:
+ case QwtSymbol::LTriangle:
+ case QwtSymbol::Star2:
+ case QwtSymbol::Hexagon:
+ {
+ d_data->brush.setColor( color );
+ break;
+ }
+ case QwtSymbol::Cross:
+ case QwtSymbol::XCross:
+ case QwtSymbol::HLine:
+ case QwtSymbol::VLine:
+ case QwtSymbol::Star1:
+ {
+ d_data->pen.setColor( color );
+ break;
+ }
+ default:
+ {
+ d_data->brush.setColor( color );
+ d_data->pen.setColor( color );
+ }
+ }
+}
+
+/*!
+ Draw an array of symbols
+
+ Painting several symbols is more effective than drawing symbols
+ one by one, as a couple of layout calculations and setting of pen/brush
+ can be done once for the complete array.
+
+ \param painter Painter
+ \param points Array of points
+ \param numPoints Number of points
+*/
+void QwtSymbol::drawSymbols( QPainter *painter,
+ const QPointF *points, int numPoints ) const
+{
+ if ( numPoints <= 0 )
+ return;
+
+ painter->save();
+
+ switch ( d_data->style )
+ {
+ case QwtSymbol::Ellipse:
+ {
+ qwtDrawEllipseSymbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Rect:
+ {
+ qwtDrawRectSymbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Diamond:
+ {
+ qwtDrawDiamondSymbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Cross:
+ {
+ qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::XCross:
+ {
+ qwtDrawXCrossSymbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Triangle:
+ case QwtSymbol::UTriangle:
+ {
+ qwtDrawTriangleSymbols( painter, QwtTriangle::Up,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::DTriangle:
+ {
+ qwtDrawTriangleSymbols( painter, QwtTriangle::Down,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::RTriangle:
+ {
+ qwtDrawTriangleSymbols( painter, QwtTriangle::Right,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::LTriangle:
+ {
+ qwtDrawTriangleSymbols( painter, QwtTriangle::Left,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::HLine:
+ {
+ qwtDrawLineSymbols( painter, Qt::Horizontal,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::VLine:
+ {
+ qwtDrawLineSymbols( painter, Qt::Vertical,
+ points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Star1:
+ {
+ qwtDrawStar1Symbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Star2:
+ {
+ qwtDrawStar2Symbols( painter, points, numPoints, *this );
+ break;
+ }
+ case QwtSymbol::Hexagon:
+ {
+ qwtDrawHexagonSymbols( painter, points, numPoints, *this );
+ break;
+ }
+ default:;
+ }
+ painter->restore();
+}
+
+//! \return Size of the bounding rectangle of a symbol
+QSize QwtSymbol::boundingSize() const
+{
+ QSizeF size;
+
+ switch ( d_data->style )
+ {
+ case QwtSymbol::Ellipse:
+ case QwtSymbol::Rect:
+ case QwtSymbol::Hexagon:
+ {
+ qreal pw = 0.0;
+ if ( d_data->pen.style() != Qt::NoPen )
+ pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
+
+ size = d_data->size + QSizeF( pw, pw );
+
+ break;
+ }
+ case QwtSymbol::XCross:
+ case QwtSymbol::Diamond:
+ case QwtSymbol::Triangle:
+ case QwtSymbol::UTriangle:
+ case QwtSymbol::DTriangle:
+ case QwtSymbol::RTriangle:
+ case QwtSymbol::LTriangle:
+ case QwtSymbol::Star1:
+ case QwtSymbol::Star2:
+ {
+ qreal pw = 0.0;
+ if ( d_data->pen.style() != Qt::NoPen )
+ pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
+
+ size = d_data->size + QSizeF( 2 * pw, 2 * pw );
+ break;
+ }
+ default:
+ {
+ size = d_data->size;
+ }
+ }
+
+ size += QSizeF( 1.0, 1.0 ); // for antialiasing
+
+ return QSize( qCeil( size.width() ), qCeil( size.height() ) );
+}
+
+/*!
+ Specify the symbol style
+
+ \param style Style
+ \sa style()
+*/
+void QwtSymbol::setStyle( QwtSymbol::Style style )
+{
+ d_data->style = style;
+}
+
+/*!
+ \return Current symbol style
+ \sa setStyle()
+*/
+QwtSymbol::Style QwtSymbol::style() const
+{
+ return d_data->style;
+}
diff --git a/src/libpcp_qwt/src/qwt_symbol.h b/src/libpcp_qwt/src/qwt_symbol.h
new file mode 100644
index 0000000..4e38431
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_symbol.h
@@ -0,0 +1,154 @@
+/* -*- 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_SYMBOL_H
+#define QWT_SYMBOL_H
+
+#include "qwt_global.h"
+#include <QPolygonF>
+
+class QPainter;
+class QRect;
+class QSize;
+class QBrush;
+class QPen;
+class QColor;
+class QPointF;
+
+//! A class for drawing symbols
+class QWT_EXPORT QwtSymbol
+{
+public:
+ /*!
+ Symbol Style
+ \sa setStyle(), style()
+ */
+ enum Style
+ {
+ //! No Style. The symbol cannot be drawn.
+ NoSymbol = -1,
+
+ //! Ellipse or circle
+ Ellipse,
+
+ //! Rectangle
+ Rect,
+
+ //! Diamond
+ Diamond,
+
+ //! Triangle pointing upwards
+ Triangle,
+
+ //! Triangle pointing downwards
+ DTriangle,
+
+ //! Triangle pointing upwards
+ UTriangle,
+
+ //! Triangle pointing left
+ LTriangle,
+
+ //! Triangle pointing right
+ RTriangle,
+
+ //! Cross (+)
+ Cross,
+
+ //! Diagonal cross (X)
+ XCross,
+
+ //! Horizontal line
+ HLine,
+
+ //! Vertical line
+ VLine,
+
+ //! X combined with +
+ Star1,
+
+ //! Six-pointed star
+ Star2,
+
+ //! Hexagon
+ Hexagon,
+
+ /*!
+ Styles >= QwtSymbol::UserSymbol are reserved for derived
+ classes of QwtSymbol that overload drawSymbols() with
+ additional application specific symbol types.
+ */
+ UserStyle = 1000
+ };
+
+public:
+ QwtSymbol( Style = NoSymbol );
+ QwtSymbol( Style, const QBrush &, const QPen &, const QSize & );
+ QwtSymbol( const QwtSymbol & );
+ virtual ~QwtSymbol();
+
+ QwtSymbol &operator=( const QwtSymbol & );
+ bool operator==( const QwtSymbol & ) const;
+ bool operator!=( const QwtSymbol & ) const;
+
+ void setSize( const QSize & );
+ void setSize( int width, int height = -1 );
+ const QSize& size() const;
+
+ virtual void setColor( const QColor & );
+
+ void setBrush( const QBrush& b );
+ const QBrush& brush() const;
+
+ void setPen( const QPen & );
+ const QPen& pen() const;
+
+ void setStyle( Style );
+ Style style() const;
+
+ void drawSymbol( QPainter *, const QPointF & ) const;
+ void drawSymbols( QPainter *, const QPolygonF & ) const;
+
+ virtual QSize boundingSize() const;
+
+protected:
+ virtual void drawSymbols( QPainter *,
+ const QPointF *, int numPoints ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+/*!
+ \brief Draw the symbol at a specified position
+
+ \param painter Painter
+ \param pos Position of the symbol in screen coordinates
+*/
+inline void QwtSymbol::drawSymbol(
+ QPainter *painter, const QPointF &pos ) const
+{
+ drawSymbols( painter, &pos, 1 );
+}
+
+/*!
+ \brief Draw symbols at the specified points
+
+ \param painter Painter
+ \param points Positions of the symbols in screen coordinates
+*/
+
+inline void QwtSymbol::drawSymbols(
+ QPainter *painter, const QPolygonF &points ) const
+{
+ drawSymbols( painter, points.data(), points.size() );
+}
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_system_clock.cpp b/src/libpcp_qwt/src/qwt_system_clock.cpp
new file mode 100644
index 0000000..4816b12
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_system_clock.cpp
@@ -0,0 +1,364 @@
+/* -*- 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_system_clock.h"
+#include <qdatetime.h>
+
+#if !defined(Q_OS_WIN)
+#include <unistd.h>
+#endif
+
+#if defined(Q_OS_MAC)
+#include <stdint.h>
+#include <mach/mach_time.h>
+#define QWT_HIGH_RESOLUTION_CLOCK
+#elif defined(_POSIX_TIMERS)
+#include <time.h>
+#define QWT_HIGH_RESOLUTION_CLOCK
+#elif defined(Q_OS_WIN)
+#define QWT_HIGH_RESOLUTION_CLOCK
+#include <qt_windows.h>
+#endif
+
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+
+class QwtHighResolutionClock
+{
+public:
+ QwtHighResolutionClock();
+
+ void start();
+ double restart();
+ double elapsed() const;
+
+ bool isNull() const;
+
+ static double precision();
+
+private:
+
+#if defined(Q_OS_MAC)
+ static double msecsTo( uint64_t, uint64_t );
+
+ uint64_t d_timeStamp;
+#elif defined(_POSIX_TIMERS)
+
+ static double msecsTo( const struct timespec &,
+ const struct timespec & );
+
+ static bool isMonotonic();
+
+ struct timespec d_timeStamp;
+ clockid_t d_clockId;
+
+#elif defined(Q_OS_WIN)
+
+ LARGE_INTEGER d_startTicks;
+ LARGE_INTEGER d_ticksPerSecond;
+#endif
+};
+
+#if defined(Q_OS_MAC)
+QwtHighResolutionClock::QwtHighResolutionClock():
+ d_timeStamp( 0 )
+{
+}
+
+double QwtHighResolutionClock::precision()
+{
+ return 1e-6;
+}
+
+void QwtHighResolutionClock::start()
+{
+ d_timeStamp = mach_absolute_time();
+}
+
+double QwtHighResolutionClock::restart()
+{
+ const uint64_t timeStamp = mach_absolute_time();
+ const double elapsed = msecsTo( d_timeStamp, timeStamp );
+ d_timeStamp = timeStamp;
+
+ return elapsed;
+}
+
+double QwtHighResolutionClock::elapsed() const
+{
+ return msecsTo( d_timeStamp, mach_absolute_time() );
+}
+
+bool QwtHighResolutionClock::isNull() const
+{
+ return d_timeStamp == 0;
+}
+
+double QwtHighResolutionClock::msecsTo(
+ uint64_t from, uint64_t to )
+{
+ const uint64_t difference = to - from;
+
+ static double conversion = 0.0;
+ if ( conversion == 0.0 )
+ {
+ mach_timebase_info_data_t info;
+ kern_return_t err = mach_timebase_info( &info );
+
+ //Convert the timebase into ms
+ if ( err == 0 )
+ conversion = 1e-6 * ( double ) info.numer / ( double ) info.denom;
+ }
+
+ return conversion * ( double ) difference;
+}
+
+#elif defined(_POSIX_TIMERS)
+
+QwtHighResolutionClock::QwtHighResolutionClock()
+{
+ d_clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+ d_timeStamp.tv_sec = d_timeStamp.tv_nsec = 0;
+}
+
+double QwtHighResolutionClock::precision()
+{
+ struct timespec resolution;
+
+ int clockId = isMonotonic() ? CLOCK_MONOTONIC : CLOCK_REALTIME;
+ ::clock_getres( clockId, &resolution );
+
+ return resolution.tv_nsec / 1e3;
+}
+
+inline bool QwtHighResolutionClock::isNull() const
+{
+ return d_timeStamp.tv_sec <= 0 && d_timeStamp.tv_nsec <= 0;
+}
+
+inline void QwtHighResolutionClock::start()
+{
+ ::clock_gettime( d_clockId, &d_timeStamp );
+}
+
+double QwtHighResolutionClock::restart()
+{
+ struct timespec timeStamp;
+ ::clock_gettime( d_clockId, &timeStamp );
+
+ const double elapsed = msecsTo( d_timeStamp, timeStamp );
+
+ d_timeStamp = timeStamp;
+ return elapsed;
+}
+
+inline double QwtHighResolutionClock::elapsed() const
+{
+ struct timespec timeStamp;
+ ::clock_gettime( d_clockId, &timeStamp );
+
+ return msecsTo( d_timeStamp, timeStamp );
+}
+
+inline double QwtHighResolutionClock::msecsTo(
+ const struct timespec &t1, const struct timespec &t2 )
+{
+ return ( t2.tv_sec - t1.tv_sec ) * 1e3
+ + ( t2.tv_nsec - t1.tv_nsec ) * 1e-6;
+}
+
+bool QwtHighResolutionClock::isMonotonic()
+{
+ // code copied from qcore_unix.cpp
+
+#if (_POSIX_MONOTONIC_CLOCK-0 > 0)
+ return true;
+#else
+ static int returnValue = 0;
+
+ if ( returnValue == 0 )
+ {
+#if (_POSIX_MONOTONIC_CLOCK-0 < 0) || !defined(_SC_MONOTONIC_CLOCK)
+ returnValue = -1;
+#elif (_POSIX_MONOTONIC_CLOCK == 0)
+ // detect if the system support monotonic timers
+ const long x = sysconf( _SC_MONOTONIC_CLOCK );
+ returnValue = ( x >= 200112L ) ? 1 : -1;
+#endif
+ }
+
+ return returnValue != -1;
+#endif
+}
+
+#elif defined(Q_OS_WIN)
+
+QwtHighResolutionClock::QwtHighResolutionClock()
+{
+ d_startTicks.QuadPart = 0;
+ QueryPerformanceFrequency( &d_ticksPerSecond );
+}
+
+double QwtHighResolutionClock::precision()
+{
+ LARGE_INTEGER ticks;
+ if ( QueryPerformanceFrequency( &ticks ) && ticks.QuadPart > 0 )
+ return 1e3 / ticks.QuadPart;
+
+ return 0.0;
+}
+
+inline bool QwtHighResolutionClock::isNull() const
+{
+ return d_startTicks.QuadPart <= 0;
+}
+
+inline void QwtHighResolutionClock::start()
+{
+ QueryPerformanceCounter( &d_startTicks );
+}
+
+inline double QwtHighResolutionClock::restart()
+{
+ LARGE_INTEGER ticks;
+ QueryPerformanceCounter( &ticks );
+
+ const double dt = ticks.QuadPart - d_startTicks.QuadPart;
+ d_startTicks = ticks;
+
+ return dt / d_ticksPerSecond.QuadPart * 1e3;
+}
+
+inline double QwtHighResolutionClock::elapsed() const
+{
+ LARGE_INTEGER ticks;
+ QueryPerformanceCounter( &ticks );
+
+ const double dt = ticks.QuadPart - d_startTicks.QuadPart;
+ return dt / d_ticksPerSecond.QuadPart * 1e3;
+}
+
+#endif
+
+#endif // QWT_HIGH_RESOLUTION_CLOCK
+
+class QwtSystemClock::PrivateData
+{
+public:
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ QwtHighResolutionClock *clock;
+#endif
+ QTime time;
+};
+
+//! Constructs a null clock object.
+QwtSystemClock::QwtSystemClock()
+{
+ d_data = new PrivateData;
+
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ d_data->clock = NULL;
+ if ( QwtHighResolutionClock::precision() > 0.0 )
+ d_data->clock = new QwtHighResolutionClock;
+#endif
+}
+
+//! Destructor
+QwtSystemClock::~QwtSystemClock()
+{
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ delete d_data->clock;
+#endif
+ delete d_data;
+}
+
+/*!
+ \return true if the clock has never been started.
+*/
+bool QwtSystemClock::isNull() const
+{
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ if ( d_data->clock )
+ return d_data->clock->isNull();
+#endif
+
+ return d_data->time.isNull();
+}
+
+/*!
+ Sets the start time to the current time.
+*/
+void QwtSystemClock::start()
+{
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ if ( d_data->clock )
+ {
+ d_data->clock->start();
+ return;
+ }
+#endif
+
+ d_data->time.start();
+}
+
+/*!
+ The start time to the current time and
+ return the time, that is elapsed since the
+ previous start time.
+*/
+double QwtSystemClock::restart()
+{
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ if ( d_data->clock )
+ return d_data->clock->restart();
+#endif
+
+ return d_data->time.restart();
+}
+
+/*!
+ \return Number of milliseconds that have elapsed since the last time
+ start() or restart() was called or 0.0 for null clocks.
+*/
+double QwtSystemClock::elapsed() const
+{
+ double elapsed = 0.0;
+
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ if ( d_data->clock )
+ {
+ if ( !d_data->clock->isNull() )
+ elapsed = d_data->clock->elapsed();
+
+ return elapsed;
+ }
+#endif
+
+ if ( !d_data->time.isNull() )
+ elapsed = d_data->time.elapsed();
+
+ return elapsed;
+}
+
+/*!
+ \return Accuracy of the system clock in milliseconds.
+*/
+double QwtSystemClock::precision()
+{
+ static double prec = 0.0;
+ if ( prec <= 0.0 )
+ {
+#if defined(QWT_HIGH_RESOLUTION_CLOCK)
+ prec = QwtHighResolutionClock::precision();
+#endif
+ if ( prec <= 0.0 )
+ prec = 1.0; // QTime offers 1 ms
+ }
+
+ return prec;
+}
diff --git a/src/libpcp_qwt/src/qwt_system_clock.h b/src/libpcp_qwt/src/qwt_system_clock.h
new file mode 100644
index 0000000..a9da150
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_system_clock.h
@@ -0,0 +1,49 @@
+/* -*- 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_SYSTEM_CLOCK_H
+#define QWT_SYSTEM_CLOCK_H
+
+#include "qwt_global.h"
+
+/*!
+ \brief QwtSystemClock provides high resolution clock time functions.
+
+ Sometimes the resolution offered by QTime ( millisecond ) is not accurate
+ enough for implementing time measurements ( f.e. sampling ).
+ QwtSystemClock offers a subset of the QTime functionality using higher
+ resolution timers ( if possible ).
+
+ Precision and time intervals are multiples of milliseconds (ms).
+
+ \note The implementation uses high-resolution performance counter on Windows,
+ mach_absolute_time() on the Mac or POSIX timers on other systems.
+ If none is available it falls back on QTimer.
+*/
+
+class QWT_EXPORT QwtSystemClock
+{
+public:
+ QwtSystemClock();
+ virtual ~QwtSystemClock();
+
+ bool isNull() const;
+
+ void start();
+ double restart();
+ double elapsed() const;
+
+ static double precision();
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_text.cpp b/src/libpcp_qwt/src/qwt_text.cpp
new file mode 100644
index 0000000..3b0ded5
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text.cpp
@@ -0,0 +1,643 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
+ * Qwt Widget Library
+ * Copyright (C) 1997 Josef Wilgen
+ * Copyright (C) 2003 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_text.h"
+#include "qwt_painter.h"
+#include "qwt_text_engine.h"
+#include <qmap.h>
+#include <qfont.h>
+#include <qcolor.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qmath.h>
+
+class QwtTextEngineDict
+{
+public:
+ static QwtTextEngineDict &dict();
+
+ void setTextEngine( QwtText::TextFormat, QwtTextEngine * );
+
+ const QwtTextEngine *textEngine( QwtText::TextFormat ) const;
+ const QwtTextEngine *textEngine( const QString &,
+ QwtText::TextFormat ) const;
+
+private:
+ QwtTextEngineDict();
+ ~QwtTextEngineDict();
+
+ typedef QMap<int, QwtTextEngine *> EngineMap;
+
+ inline const QwtTextEngine *engine( EngineMap::const_iterator &it ) const
+ {
+ return it.value();
+ }
+
+ EngineMap d_map;
+};
+
+QwtTextEngineDict &QwtTextEngineDict::dict()
+{
+ static QwtTextEngineDict engineDict;
+ return engineDict;
+}
+
+QwtTextEngineDict::QwtTextEngineDict()
+{
+ d_map.insert( QwtText::PlainText, new QwtPlainTextEngine() );
+#ifndef QT_NO_RICHTEXT
+ d_map.insert( QwtText::RichText, new QwtRichTextEngine() );
+#endif
+}
+
+QwtTextEngineDict::~QwtTextEngineDict()
+{
+ for ( EngineMap::const_iterator it = d_map.begin();
+ it != d_map.end(); ++it )
+ {
+ const QwtTextEngine *textEngine = engine( it );
+ delete textEngine;
+ }
+}
+
+const QwtTextEngine *QwtTextEngineDict::textEngine( const QString& text,
+ QwtText::TextFormat format ) const
+{
+ if ( format == QwtText::AutoText )
+ {
+ for ( EngineMap::const_iterator it = d_map.begin();
+ it != d_map.end(); ++it )
+ {
+ if ( it.key() != QwtText::PlainText )
+ {
+ const QwtTextEngine *e = engine( it );
+ if ( e && e->mightRender( text ) )
+ return e;
+ }
+ }
+ }
+
+ EngineMap::const_iterator it = d_map.find( format );
+ if ( it != d_map.end() )
+ {
+ const QwtTextEngine *e = engine( it );
+ if ( e )
+ return e;
+ }
+
+ it = d_map.find( QwtText::PlainText );
+ return engine( it );
+}
+
+void QwtTextEngineDict::setTextEngine( QwtText::TextFormat format,
+ QwtTextEngine *engine )
+{
+ if ( format == QwtText::AutoText )
+ return;
+
+ if ( format == QwtText::PlainText && engine == NULL )
+ return;
+
+ EngineMap::const_iterator it = d_map.find( format );
+ if ( it != d_map.end() )
+ {
+ const QwtTextEngine *e = this->engine( it );
+ if ( e )
+ delete e;
+
+ d_map.remove( format );
+ }
+
+ if ( engine != NULL )
+ d_map.insert( format, engine );
+}
+
+const QwtTextEngine *QwtTextEngineDict::textEngine(
+ QwtText::TextFormat format ) const
+{
+ const QwtTextEngine *e = NULL;
+
+ EngineMap::const_iterator it = d_map.find( format );
+ if ( it != d_map.end() )
+ e = engine( it );
+
+ return e;
+}
+
+class QwtText::PrivateData
+{
+public:
+ PrivateData():
+ renderFlags( Qt::AlignCenter ),
+ backgroundPen( Qt::NoPen ),
+ backgroundBrush( Qt::NoBrush ),
+ paintAttributes( 0 ),
+ layoutAttributes( 0 ),
+ textEngine( NULL )
+ {
+ }
+
+ int renderFlags;
+ QString text;
+ QFont font;
+ QColor color;
+ QPen backgroundPen;
+ QBrush backgroundBrush;
+
+ QwtText::PaintAttributes paintAttributes;
+ QwtText::LayoutAttributes layoutAttributes;
+
+ const QwtTextEngine *textEngine;
+};
+
+class QwtText::LayoutCache
+{
+public:
+ void invalidate()
+ {
+ textSize = QSizeF();
+ }
+
+ QFont font;
+ QSizeF textSize;
+};
+
+/*!
+ Constructor
+
+ \param text Text content
+ \param textFormat Text format
+*/
+QwtText::QwtText( const QString &text, QwtText::TextFormat textFormat )
+{
+ d_data = new PrivateData;
+ d_data->text = text;
+ d_data->textEngine = textEngine( text, textFormat );
+
+ d_layoutCache = new LayoutCache;
+}
+
+//! Copy constructor
+QwtText::QwtText( const QwtText &other )
+{
+ d_data = new PrivateData;
+ *d_data = *other.d_data;
+
+ d_layoutCache = new LayoutCache;
+ *d_layoutCache = *other.d_layoutCache;
+}
+
+//! Destructor
+QwtText::~QwtText()
+{
+ delete d_data;
+ delete d_layoutCache;
+}
+
+//! Assignment operator
+QwtText &QwtText::operator=( const QwtText & other )
+{
+ *d_data = *other.d_data;
+ *d_layoutCache = *other.d_layoutCache;
+ return *this;
+}
+
+//! Relational operator
+bool QwtText::operator==( const QwtText &other ) const
+{
+ return d_data->renderFlags == other.d_data->renderFlags &&
+ d_data->text == other.d_data->text &&
+ d_data->font == other.d_data->font &&
+ d_data->color == other.d_data->color &&
+ d_data->backgroundPen == other.d_data->backgroundPen &&
+ d_data->backgroundBrush == other.d_data->backgroundBrush &&
+ d_data->paintAttributes == other.d_data->paintAttributes &&
+ d_data->textEngine == other.d_data->textEngine;
+}
+
+//! Relational operator
+bool QwtText::operator!=( const QwtText &other ) const // invalidate
+{
+ return !( other == *this );
+}
+
+/*!
+ Assign a new text content
+
+ \param text Text content
+ \param textFormat Text format
+
+ \sa text()
+*/
+void QwtText::setText( const QString &text,
+ QwtText::TextFormat textFormat )
+{
+ d_data->text = text;
+ d_data->textEngine = textEngine( text, textFormat );
+ d_layoutCache->invalidate();
+}
+
+/*!
+ Return the text.
+ \sa setText()
+*/
+QString QwtText::text() const
+{
+ return d_data->text;
+}
+
+/*!
+ \brief Change the render flags
+
+ The default setting is Qt::AlignCenter
+
+ \param renderFlags Bitwise OR of the flags used like in QPainter::drawText
+
+ \sa renderFlags(), QwtTextEngine::draw()
+ \note Some renderFlags might have no effect, depending on the text format.
+*/
+void QwtText::setRenderFlags( int renderFlags )
+{
+ if ( renderFlags != d_data->renderFlags )
+ {
+ d_data->renderFlags = renderFlags;
+ d_layoutCache->invalidate();
+ }
+}
+
+/*!
+ \return Render flags
+ \sa setRenderFlags()
+*/
+int QwtText::renderFlags() const
+{
+ return d_data->renderFlags;
+}
+
+/*!
+ Set the font.
+
+ \param font Font
+ \note Setting the font might have no effect, when
+ the text contains control sequences for setting fonts.
+*/
+void QwtText::setFont( const QFont &font )
+{
+ d_data->font = font;
+ setPaintAttribute( PaintUsingTextFont );
+}
+
+//! Return the font.
+QFont QwtText::font() const
+{
+ return d_data->font;
+}
+
+/*!
+ Return the font of the text, if it has one.
+ Otherwise return defaultFont.
+
+ \param defaultFont Default font
+ \sa setFont(), font(), PaintAttributes
+*/
+QFont QwtText::usedFont( const QFont &defaultFont ) const
+{
+ if ( d_data->paintAttributes & PaintUsingTextFont )
+ return d_data->font;
+
+ return defaultFont;
+}
+
+/*!
+ Set the pen color used for painting the text.
+
+ \param color Color
+ \note Setting the color might have no effect, when
+ the text contains control sequences for setting colors.
+*/
+void QwtText::setColor( const QColor &color )
+{
+ d_data->color = color;
+ setPaintAttribute( PaintUsingTextColor );
+}
+
+//! Return the pen color, used for painting the text
+QColor QwtText::color() const
+{
+ return d_data->color;
+}
+
+/*!
+ Return the color of the text, if it has one.
+ Otherwise return defaultColor.
+
+ \param defaultColor Default color
+ \sa setColor(), color(), PaintAttributes
+*/
+QColor QwtText::usedColor( const QColor &defaultColor ) const
+{
+ if ( d_data->paintAttributes & PaintUsingTextColor )
+ return d_data->color;
+
+ return defaultColor;
+}
+
+/*!
+ Set the background pen
+
+ \param pen Background pen
+ \sa backgroundPen(), setBackgroundBrush()
+*/
+void QwtText::setBackgroundPen( const QPen &pen )
+{
+ d_data->backgroundPen = pen;
+ setPaintAttribute( PaintBackground );
+}
+
+/*!
+ \return Background pen
+ \sa setBackgroundPen(), backgroundBrush()
+*/
+QPen QwtText::backgroundPen() const
+{
+ return d_data->backgroundPen;
+}
+
+/*!
+ Set the background brush
+
+ \param brush Background brush
+ \sa backgroundBrush(), setBackgroundPen()
+*/
+void QwtText::setBackgroundBrush( const QBrush &brush )
+{
+ d_data->backgroundBrush = brush;
+ setPaintAttribute( PaintBackground );
+}
+
+/*!
+ \return Background brush
+ \sa setBackgroundBrush(), backgroundPen()
+*/
+QBrush QwtText::backgroundBrush() const
+{
+ return d_data->backgroundBrush;
+}
+
+/*!
+ Change a paint attribute
+
+ \param attribute Paint attribute
+ \param on On/Off
+
+ \note Used by setFont(), setColor(),
+ setBackgroundPen() and setBackgroundBrush()
+ \sa testPaintAttribute()
+*/
+void QwtText::setPaintAttribute( PaintAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->paintAttributes |= attribute;
+ else
+ d_data->paintAttributes &= ~attribute;
+}
+
+/*!
+ Test a paint attribute
+
+ \param attribute Paint attribute
+ \return true, if attribute is enabled
+
+ \sa setPaintAttribute()
+*/
+bool QwtText::testPaintAttribute( PaintAttribute attribute ) const
+{
+ return d_data->paintAttributes & attribute;
+}
+
+/*!
+ Change a layout attribute
+
+ \param attribute Layout attribute
+ \param on On/Off
+ \sa testLayoutAttribute()
+*/
+void QwtText::setLayoutAttribute( LayoutAttribute attribute, bool on )
+{
+ if ( on )
+ d_data->layoutAttributes |= attribute;
+ else
+ d_data->layoutAttributes &= ~attribute;
+}
+
+/*!
+ Test a layout attribute
+
+ \param attribute Layout attribute
+ \return true, if attribute is enabled
+
+ \sa setLayoutAttribute()
+*/
+bool QwtText::testLayoutAttribute( LayoutAttribute attribute ) const
+{
+ return d_data->layoutAttributes | attribute;
+}
+
+/*!
+ Find the height for a given width
+
+ \param defaultFont Font, used for the calculation if the text has no font
+ \param width Width
+
+ \return Calculated height
+*/
+double QwtText::heightForWidth( double width, const QFont &defaultFont ) const
+{
+ // We want to calculate in screen metrics. So
+ // we need a font that uses screen metrics
+
+ const QFont font( usedFont( defaultFont ), QApplication::desktop() );
+
+ double h = 0;
+
+ if ( d_data->layoutAttributes & MinimumLayout )
+ {
+ double left, right, top, bottom;
+ d_data->textEngine->textMargins( font, d_data->text,
+ left, right, top, bottom );
+
+ h = d_data->textEngine->heightForWidth(
+ font, d_data->renderFlags, d_data->text,
+ width + left + right );
+
+ h -= top + bottom;
+ }
+ else
+ {
+ h = d_data->textEngine->heightForWidth(
+ font, d_data->renderFlags, d_data->text, width );
+ }
+
+ return h;
+}
+
+/*!
+ Find the height for a given width
+
+ \param defaultFont Font, used for the calculation if the text has no font
+
+ \return Calculated height
+*/
+
+/*!
+ Returns the size, that is needed to render text
+
+ \param defaultFont Font of the text
+ \return Caluclated size
+*/
+QSizeF QwtText::textSize( const QFont &defaultFont ) const
+{
+ // We want to calculate in screen metrics. So
+ // we need a font that uses screen metrics
+
+ const QFont font( usedFont( defaultFont ), QApplication::desktop() );
+
+ if ( !d_layoutCache->textSize.isValid()
+ || d_layoutCache->font != font )
+ {
+ d_layoutCache->textSize = d_data->textEngine->textSize(
+ font, d_data->renderFlags, d_data->text );
+ d_layoutCache->font = font;
+ }
+
+ QSizeF sz = d_layoutCache->textSize;
+
+ if ( d_data->layoutAttributes & MinimumLayout )
+ {
+ double left, right, top, bottom;
+ d_data->textEngine->textMargins( font, d_data->text,
+ left, right, top, bottom );
+ sz -= QSizeF( left + right, top + bottom );
+ }
+
+ return sz;
+}
+
+/*!
+ Draw a text into a rectangle
+
+ \param painter Painter
+ \param rect Rectangle
+*/
+void QwtText::draw( QPainter *painter, const QRectF &rect ) const
+{
+ if ( d_data->paintAttributes & PaintBackground )
+ {
+ if ( d_data->backgroundPen != Qt::NoPen ||
+ d_data->backgroundBrush != Qt::NoBrush )
+ {
+ painter->save();
+ painter->setPen( d_data->backgroundPen );
+ painter->setBrush( d_data->backgroundBrush );
+ QwtPainter::drawRect( painter, rect );
+ painter->restore();
+ }
+ }
+
+ painter->save();
+
+ if ( d_data->paintAttributes & PaintUsingTextFont )
+ {
+ painter->setFont( d_data->font );
+ }
+
+ if ( d_data->paintAttributes & PaintUsingTextColor )
+ {
+ if ( d_data->color.isValid() )
+ painter->setPen( d_data->color );
+ }
+
+ QRectF expandedRect = rect;
+ if ( d_data->layoutAttributes & MinimumLayout )
+ {
+ // We want to calculate in screen metrics. So
+ // we need a font that uses screen metrics
+
+ const QFont font( painter->font(), QApplication::desktop() );
+
+ double left, right, top, bottom;
+ d_data->textEngine->textMargins(
+ font, d_data->text, left, right, top, bottom );
+
+ expandedRect.setTop( rect.top() - top );
+ expandedRect.setBottom( rect.bottom() + bottom );
+ expandedRect.setLeft( rect.left() - left );
+ expandedRect.setRight( rect.right() + right );
+ }
+
+ d_data->textEngine->draw( painter, expandedRect,
+ d_data->renderFlags, d_data->text );
+
+ painter->restore();
+}
+
+/*!
+ Find the text engine for a text format
+
+ In case of QwtText::AutoText the first text engine
+ (beside QwtPlainTextEngine) is returned, where QwtTextEngine::mightRender
+ returns true. If there is none QwtPlainTextEngine is returnd.
+
+ If no text engine is registered for the format QwtPlainTextEngine
+ is returnd.
+
+ \param text Text, needed in case of AutoText
+ \param format Text format
+*/
+const QwtTextEngine *QwtText::textEngine( const QString &text,
+ QwtText::TextFormat format )
+{
+ return QwtTextEngineDict::dict().textEngine( text, format );
+}
+
+/*!
+ Assign/Replace a text engine for a text format
+
+ With setTextEngine it is possible to extend Qwt with
+ other types of text formats.
+
+ For QwtText::PlainText it is not allowed to assign a engine == NULL.
+
+ \param format Text format
+ \param engine Text engine
+
+ \sa QwtMathMLTextEngine
+ \warning Using QwtText::AutoText does nothing.
+*/
+void QwtText::setTextEngine( QwtText::TextFormat format,
+ QwtTextEngine *engine )
+{
+ QwtTextEngineDict::dict().setTextEngine( format, engine );
+}
+
+/*!
+ \brief Find the text engine for a text format
+
+ textEngine can be used to find out if a text format is supported.
+
+ \param format Text format
+ \return The text engine, or NULL if no engine is available.
+*/
+const QwtTextEngine *QwtText::textEngine( QwtText::TextFormat format )
+{
+ return QwtTextEngineDict::dict().textEngine( format );
+}
diff --git a/src/libpcp_qwt/src/qwt_text.h b/src/libpcp_qwt/src/qwt_text.h
new file mode 100644
index 0000000..3c6a438
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text.h
@@ -0,0 +1,216 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
+ * Qwt Widget Library
+ * Copyright (C) 1997 Josef Wilgen
+ * Copyright (C) 2003 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_TEXT_H
+#define QWT_TEXT_H
+
+#include "qwt_global.h"
+#include <qstring.h>
+#include <qsize.h>
+#include <qfont.h>
+
+class QColor;
+class QPen;
+class QBrush;
+class QRectF;
+class QPainter;
+class QwtTextEngine;
+
+/*!
+ \brief A class representing a text
+
+ A QwtText is a text including a set of attributes how to render it.
+
+ - Format\n
+ A text might include control sequences (f.e tags) describing
+ how to render it. Each format (f.e MathML, TeX, Qt Rich Text)
+ has its own set of control sequences, that can be handles by
+ a QwtTextEngine for this format.
+ - Background\n
+ A text might have a background, defined by a QPen and QBrush
+ to improve its visibility.
+ - Font\n
+ A text might have an individual font.
+ - Color\n
+ A text might have an individual color.
+ - Render Flags\n
+ Flags from Qt::AlignmentFlag and Qt::TextFlag used like in
+ QPainter::drawText.
+
+ \sa QwtTextEngine, QwtTextLabel
+*/
+
+class QWT_EXPORT QwtText
+{
+public:
+
+ /*!
+ \brief Text format
+
+ The text format defines the QwtTextEngine, that is used to render
+ the text.
+
+ \sa QwtTextEngine, setTextEngine()
+ */
+
+ enum TextFormat
+ {
+ /*!
+ The text format is determined using QwtTextEngine::mightRender for
+ all available text engines in increasing order > PlainText.
+ If none of the text engines can render the text is rendered
+ like QwtText::PlainText.
+ */
+ AutoText = 0,
+
+ //! Draw the text as it is, using a QwtPlainTextEngine.
+ PlainText,
+
+ //! Use the Scribe framework (Qt Rich Text) to render the text.
+ RichText,
+
+ /*!
+ Use a MathML (http://en.wikipedia.org/wiki/MathML) render engine
+ to display the text. The Qwt MathML extension offers such an engine
+ based on the MathML renderer of the Qt solutions package.
+ To enable MathML support the following code needs to be added to the
+ application:
+\verbatim QwtText::setTextEngine(QwtText::MathMLText, new QwtMathMLTextEngine()); \endverbatim
+ */
+ MathMLText,
+
+ /*!
+ Use a TeX (http://en.wikipedia.org/wiki/TeX) render engine
+ to display the text ( not implemented yet ).
+ */
+ TeXText,
+
+ /*!
+ The number of text formats can be extended using setTextEngine.
+ Formats >= QwtText::OtherFormat are not used by Qwt.
+ */
+ OtherFormat = 100
+ };
+
+ /*!
+ \brief Paint Attributes
+
+ Font and color and background are optional attributes of a QwtText.
+ The paint attributes hold the information, if they are set.
+ */
+ enum PaintAttribute
+ {
+ //! The text has an individual font.
+ PaintUsingTextFont = 0x01,
+
+ //! The text has an individual color.
+ PaintUsingTextColor = 0x02,
+
+ //! The text has an individual background.
+ PaintBackground = 0x04
+ };
+
+ //! Paint attributes
+ typedef QFlags<PaintAttribute> PaintAttributes;
+
+ /*!
+ \brief Layout Attributes
+ The layout attributes affects some aspects of the layout of the text.
+ */
+ enum LayoutAttribute
+ {
+ /*!
+ Layout the text without its margins. This mode is useful if a
+ text needs to be aligned accurately, like the tick labels of a scale.
+ If QwtTextEngine::textMargins is not implemented for the format
+ of the text, MinimumLayout has no effect.
+ */
+ MinimumLayout = 0x01
+ };
+
+ //! Layout attributes
+ typedef QFlags<LayoutAttribute> LayoutAttributes;
+
+ QwtText( const QString & = QString::null,
+ TextFormat textFormat = AutoText );
+ QwtText( const QwtText & );
+ ~QwtText();
+
+ QwtText &operator=( const QwtText & );
+
+ bool operator==( const QwtText & ) const;
+ bool operator!=( const QwtText & ) const;
+
+ void setText( const QString &,
+ QwtText::TextFormat textFormat = AutoText );
+ QString text() const;
+
+ bool isNull() const;
+ bool isEmpty() const;
+
+ void setFont( const QFont & );
+ QFont font() const;
+
+ QFont usedFont( const QFont & ) const;
+
+ void setRenderFlags( int flags );
+ int renderFlags() const;
+
+ void setColor( const QColor & );
+ QColor color() const;
+
+ QColor usedColor( const QColor & ) const;
+
+ void setBackgroundPen( const QPen & );
+ QPen backgroundPen() const;
+
+ void setBackgroundBrush( const QBrush & );
+ QBrush backgroundBrush() const;
+
+ void setPaintAttribute( PaintAttribute, bool on = true );
+ bool testPaintAttribute( PaintAttribute ) const;
+
+ void setLayoutAttribute( LayoutAttribute, bool on = true );
+ bool testLayoutAttribute( LayoutAttribute ) const;
+
+ double heightForWidth( double width, const QFont & = QFont() ) const;
+ QSizeF textSize( const QFont & = QFont() ) const;
+
+ void draw( QPainter *painter, const QRectF &rect ) const;
+
+ static const QwtTextEngine *textEngine(
+ const QString &text, QwtText::TextFormat = AutoText );
+
+ static const QwtTextEngine *textEngine( QwtText::TextFormat );
+ static void setTextEngine( QwtText::TextFormat, QwtTextEngine * );
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+
+ class LayoutCache;
+ LayoutCache *d_layoutCache;
+};
+
+//! \return text().isNull()
+inline bool QwtText::isNull() const
+{
+ return text().isNull();
+}
+
+//! \return text().isEmpty()
+inline bool QwtText::isEmpty() const
+{
+ return text().isEmpty();
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtText::PaintAttributes )
+Q_DECLARE_OPERATORS_FOR_FLAGS( QwtText::LayoutAttributes )
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_text_engine.cpp b/src/libpcp_qwt/src/qwt_text_engine.cpp
new file mode 100644
index 0000000..ec74512
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text_engine.cpp
@@ -0,0 +1,344 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
+ * Qwt Widget Library
+ * Copyright (C) 1997 Josef Wilgen
+ * Copyright (C) 2003 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_text_engine.h"
+#include "qwt_math.h"
+#include "qwt_painter.h"
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qmap.h>
+#include <qwidget.h>
+#include <qtextobject.h>
+#include <qtextdocument.h>
+#include <qabstracttextdocumentlayout.h>
+
+static QString taggedRichText( const QString &text, int flags )
+{
+ QString richText = text;
+
+ // By default QSimpleRichText is Qt::AlignLeft
+ if ( flags & Qt::AlignJustify )
+ {
+ richText.prepend( QString::fromLatin1( "<div align=\"justify\">" ) );
+ richText.append( QString::fromLatin1( "</div>" ) );
+ }
+ else if ( flags & Qt::AlignRight )
+ {
+ richText.prepend( QString::fromLatin1( "<div align=\"right\">" ) );
+ richText.append( QString::fromLatin1( "</div>" ) );
+ }
+ else if ( flags & Qt::AlignHCenter )
+ {
+ richText.prepend( QString::fromLatin1( "<div align=\"center\">" ) );
+ richText.append( QString::fromLatin1( "</div>" ) );
+ }
+
+ return richText;
+}
+
+class QwtRichTextDocument: public QTextDocument
+{
+public:
+ QwtRichTextDocument( const QString &text, int flags, const QFont &font )
+ {
+ setUndoRedoEnabled( false );
+ setDefaultFont( font );
+ setHtml( text );
+
+ // make sure we have a document layout
+ ( void )documentLayout();
+
+ QTextOption option = defaultTextOption();
+ if ( flags & Qt::TextWordWrap )
+ option.setWrapMode( QTextOption::WordWrap );
+ else
+ option.setWrapMode( QTextOption::NoWrap );
+
+ option.setAlignment( ( Qt::Alignment ) flags );
+ setDefaultTextOption( option );
+
+ QTextFrame *root = rootFrame();
+ QTextFrameFormat fm = root->frameFormat();
+ fm.setBorder( 0 );
+ fm.setMargin( 0 );
+ fm.setPadding( 0 );
+ fm.setBottomMargin( 0 );
+ fm.setLeftMargin( 0 );
+ root->setFrameFormat( fm );
+
+ adjustSize();
+ }
+};
+
+class QwtPlainTextEngine::PrivateData
+{
+public:
+ int effectiveAscent( const QFont &font ) const
+ {
+ const QString fontKey = font.key();
+
+ QMap<QString, int>::const_iterator it =
+ d_ascentCache.find( fontKey );
+ if ( it == d_ascentCache.end() )
+ {
+ int ascent = findAscent( font );
+ it = d_ascentCache.insert( fontKey, ascent );
+ }
+
+ return ( *it );
+ }
+
+private:
+ int findAscent( const QFont &font ) const
+ {
+ static const QString dummy( "E" );
+ static const QColor white( Qt::white );
+
+ const QFontMetrics fm( font );
+ QPixmap pm( fm.width( dummy ), fm.height() );
+ pm.fill( white );
+
+ QPainter p( &pm );
+ p.setFont( font );
+ p.drawText( 0, 0, pm.width(), pm.height(), 0, dummy );
+ p.end();
+
+ const QImage img = pm.toImage();
+
+ int row = 0;
+ for ( row = 0; row < img.height(); row++ )
+ {
+ const QRgb *line = ( const QRgb * )img.scanLine( row );
+
+ const int w = pm.width();
+ for ( int col = 0; col < w; col++ )
+ {
+ if ( line[col] != white.rgb() )
+ return fm.ascent() - row + 1;
+ }
+ }
+
+ return fm.ascent();
+ }
+
+ mutable QMap<QString, int> d_ascentCache;
+};
+
+//! Constructor
+QwtTextEngine::QwtTextEngine()
+{
+}
+
+//! Destructor
+QwtTextEngine::~QwtTextEngine()
+{
+}
+
+//! Constructor
+QwtPlainTextEngine::QwtPlainTextEngine()
+{
+ d_data = new PrivateData;
+}
+
+//! Destructor
+QwtPlainTextEngine::~QwtPlainTextEngine()
+{
+ delete d_data;
+}
+
+/*!
+ Find the height for a given width
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+ \param width Width
+
+ \return Calculated height
+*/
+double QwtPlainTextEngine::heightForWidth( const QFont& font, int flags,
+ const QString& text, double width ) const
+{
+ const QFontMetricsF fm( font );
+ const QRectF rect = fm.boundingRect(
+ QRectF( 0, 0, width, QWIDGETSIZE_MAX ), flags, text );
+
+ return rect.height();
+}
+
+/*!
+ Returns the size, that is needed to render text
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+
+ \return Caluclated size
+*/
+QSizeF QwtPlainTextEngine::textSize( const QFont &font,
+ int flags, const QString& text ) const
+{
+ const QFontMetricsF fm( font );
+ const QRectF rect = fm.boundingRect(
+ QRectF( 0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX ), flags, text );
+
+ return rect.size();
+}
+
+/*!
+ Return margins around the texts
+
+ \param font Font of the text
+ \param left Return 0
+ \param right Return 0
+ \param top Return value for the top margin
+ \param bottom Return value for the bottom margin
+*/
+void QwtPlainTextEngine::textMargins( const QFont &font, const QString &,
+ double &left, double &right, double &top, double &bottom ) const
+{
+ left = right = top = 0;
+
+ const QFontMetricsF fm( font );
+ top = fm.ascent() - d_data->effectiveAscent( font );
+ bottom = fm.descent();
+}
+
+/*!
+ \brief Draw the text in a clipping rectangle
+
+ A wrapper for QPainter::drawText.
+
+ \param painter Painter
+ \param rect Clipping rectangle
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+*/
+void QwtPlainTextEngine::draw( QPainter *painter, const QRectF &rect,
+ int flags, const QString& text ) const
+{
+ QwtPainter::drawText( painter, rect, flags, text );
+}
+
+/*!
+ Test if a string can be rendered by this text engine.
+ \return Always true. All texts can be rendered by QwtPlainTextEngine
+*/
+bool QwtPlainTextEngine::mightRender( const QString & ) const
+{
+ return true;
+}
+
+#ifndef QT_NO_RICHTEXT
+
+//! Constructor
+QwtRichTextEngine::QwtRichTextEngine()
+{
+}
+
+/*!
+ Find the height for a given width
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+ \param width Width
+
+ \return Calculated height
+*/
+double QwtRichTextEngine::heightForWidth( const QFont& font, int flags,
+ const QString& text, double width ) const
+{
+ QwtRichTextDocument doc( text, flags, font );
+
+ doc.setPageSize( QSizeF( width, QWIDGETSIZE_MAX ) );
+ return doc.documentLayout()->documentSize().height();
+}
+
+/*!
+ Returns the size, that is needed to render text
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+
+ \return Caluclated size
+*/
+
+QSizeF QwtRichTextEngine::textSize( const QFont &font,
+ int flags, const QString& text ) const
+{
+ QwtRichTextDocument doc( text, flags, font );
+
+ QTextOption option = doc.defaultTextOption();
+ if ( option.wrapMode() != QTextOption::NoWrap )
+ {
+ option.setWrapMode( QTextOption::NoWrap );
+ doc.setDefaultTextOption( option );
+ doc.adjustSize();
+ }
+
+ return doc.size();
+}
+
+/*!
+ Draw the text in a clipping rectangle
+
+ \param painter Painter
+ \param rect Clipping rectangle
+ \param flags Bitwise OR of the flags like in for QPainter::drawText
+ \param text Text to be rendered
+*/
+void QwtRichTextEngine::draw( QPainter *painter, const QRectF &rect,
+ int flags, const QString& text ) const
+{
+ QwtRichTextDocument doc( text, flags, painter->font() );
+ QwtPainter::drawSimpleRichText( painter, rect, flags, doc );
+}
+
+/*!
+ Wrap text into <div align=...> </div> tags according flags
+
+ \param text Text
+ \param flags Bitwise OR of the flags like in for QPainter::drawText
+
+ \return Tagged text
+*/
+QString QwtRichTextEngine::taggedText( const QString &text, int flags ) const
+{
+ return taggedRichText( text, flags );
+}
+
+/*!
+ Test if a string can be rendered by this text engine
+
+ \param text Text to be tested
+ \return QStyleSheet::mightBeRichText(text);
+*/
+bool QwtRichTextEngine::mightRender( const QString &text ) const
+{
+ return Qt::mightBeRichText( text );
+}
+
+/*!
+ Return margins around the texts
+
+ \param left Return 0
+ \param right Return 0
+ \param top Return 0
+ \param bottom Return 0
+*/
+void QwtRichTextEngine::textMargins( const QFont &, const QString &,
+ double &left, double &right, double &top, double &bottom ) const
+{
+ left = right = top = bottom = 0;
+}
+
+#endif // !QT_NO_RICHTEXT
diff --git a/src/libpcp_qwt/src/qwt_text_engine.h b/src/libpcp_qwt/src/qwt_text_engine.h
new file mode 100644
index 0000000..e378acf
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text_engine.h
@@ -0,0 +1,172 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
+ * Qwt Widget Library
+ * Copyright (C) 1997 Josef Wilgen
+ * Copyright (C) 2003 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_TEXT_ENGINE_H
+#define QWT_TEXT_ENGINE_H 1
+
+#include "qwt_global.h"
+#include <qsize.h>
+
+class QFont;
+class QRectF;
+class QString;
+class QPainter;
+
+/*!
+ \brief Abstract base class for rendering text strings
+
+ A text engine is responsible for rendering texts for a
+ specific text format. They are used by QwtText to render a text.
+
+ QwtPlainTextEngine and QwtRichTextEngine are part of the Qwt library.
+ The implementation of QwtMathMLTextEngine uses code from the
+ Qt solution package. Because of license implications it is built into
+ a separate library.
+
+ \sa QwtText::setTextEngine()
+*/
+
+class QWT_EXPORT QwtTextEngine
+{
+public:
+ virtual ~QwtTextEngine();
+
+ /*!
+ Find the height for a given width
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags used like in QPainter::drawText
+ \param text Text to be rendered
+ \param width Width
+
+ \return Calculated height
+ */
+ virtual double heightForWidth( const QFont &font, int flags,
+ const QString &text, double width ) const = 0;
+
+ /*!
+ Returns the size, that is needed to render text
+
+ \param font Font of the text
+ \param flags Bitwise OR of the flags like in for QPainter::drawText
+ \param text Text to be rendered
+
+ \return Caluclated size
+ */
+ virtual QSizeF textSize( const QFont &font, int flags,
+ const QString &text ) const = 0;
+
+ /*!
+ Test if a string can be rendered by this text engine
+
+ \param text Text to be tested
+ \return true, if it can be rendered
+ */
+ virtual bool mightRender( const QString &text ) const = 0;
+
+ /*!
+ Return margins around the texts
+
+ The textSize might include margins around the
+ text, like QFontMetrics::descent. In situations
+ where texts need to be aligend in detail, knowing
+ these margins might improve the layout calculations.
+
+ \param font Font of the text
+ \param text Text to be rendered
+ \param left Return value for the left margin
+ \param right Return value for the right margin
+ \param top Return value for the top margin
+ \param bottom Return value for the bottom margin
+ */
+ virtual void textMargins( const QFont &font, const QString &text,
+ double &left, double &right, double &top, double &bottom ) const = 0;
+
+ /*!
+ Draw the text in a clipping rectangle
+
+ \param painter Painter
+ \param rect Clipping rectangle
+ \param flags Bitwise OR of the flags like in for QPainter::drawText
+ \param text Text to be rendered
+ */
+ virtual void draw( QPainter *painter, const QRectF &rect,
+ int flags, const QString &text ) const = 0;
+
+protected:
+ QwtTextEngine();
+};
+
+
+/*!
+ \brief A text engine for plain texts
+
+ QwtPlainTextEngine renders texts using the basic Qt classes
+ QPainter and QFontMetrics.
+*/
+class QWT_EXPORT QwtPlainTextEngine: public QwtTextEngine
+{
+public:
+ QwtPlainTextEngine();
+ virtual ~QwtPlainTextEngine();
+
+ virtual double heightForWidth( const QFont &font, int flags,
+ const QString &text, double width ) const;
+
+ virtual QSizeF textSize( const QFont &font, int flags,
+ const QString &text ) const;
+
+ virtual void draw( QPainter *painter, const QRectF &rect,
+ int flags, const QString &text ) const;
+
+ virtual bool mightRender( const QString & ) const;
+
+ virtual void textMargins( const QFont &, const QString &,
+ double &left, double &right, double &top, double &bottom ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+
+#ifndef QT_NO_RICHTEXT
+
+/*!
+ \brief A text engine for Qt rich texts
+
+ QwtRichTextEngine renders Qt rich texts using the classes
+ of the Scribe framework of Qt.
+*/
+class QWT_EXPORT QwtRichTextEngine: public QwtTextEngine
+{
+public:
+ QwtRichTextEngine();
+
+ virtual double heightForWidth( const QFont &font, int flags,
+ const QString &text, double width ) const;
+
+ virtual QSizeF textSize( const QFont &font, int flags,
+ const QString &text ) const;
+
+ virtual void draw( QPainter *painter, const QRectF &rect,
+ int flags, const QString &text ) const;
+
+ virtual bool mightRender( const QString & ) const;
+
+ virtual void textMargins( const QFont &, const QString &,
+ double &left, double &right, double &top, double &bottom ) const;
+
+private:
+ QString taggedText( const QString &, int flags ) const;
+};
+
+#endif // !QT_NO_RICHTEXT
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_text_label.cpp b/src/libpcp_qwt/src/qwt_text_label.cpp
new file mode 100644
index 0000000..e895928
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text_label.cpp
@@ -0,0 +1,306 @@
+/* -*- 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_text_label.h"
+#include "qwt_text.h"
+#include "qwt_painter.h"
+#include <qpainter.h>
+#include <qevent.h>
+#include <qmath.h>
+
+class QwtTextLabel::PrivateData
+{
+public:
+ PrivateData():
+ indent( 4 ),
+ margin( 0 )
+ {
+ }
+
+ int indent;
+ int margin;
+ QwtText text;
+};
+
+/*!
+ Constructs an empty label.
+ \param parent Parent widget
+*/
+QwtTextLabel::QwtTextLabel( QWidget *parent ):
+ QFrame( parent )
+{
+ init();
+}
+
+/*!
+ Constructs a label that displays the text, text
+ \param parent Parent widget
+ \param text Text
+*/
+QwtTextLabel::QwtTextLabel( const QwtText &text, QWidget *parent ):
+ QFrame( parent )
+{
+ init();
+ d_data->text = text;
+}
+
+//! Destructor
+QwtTextLabel::~QwtTextLabel()
+{
+ delete d_data;
+}
+
+void QwtTextLabel::init()
+{
+ d_data = new PrivateData();
+ setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+}
+
+/*!
+ Change the label's text, keeping all other QwtText attributes
+ \param text New text
+ \param textFormat Format of text
+
+ \sa QwtText
+*/
+void QwtTextLabel::setText( const QString &text, QwtText::TextFormat textFormat )
+{
+ d_data->text.setText( text, textFormat );
+
+ update();
+ updateGeometry();
+}
+
+/*!
+ Change the label's text
+ \param text New text
+*/
+void QwtTextLabel::setText( const QwtText &text )
+{
+ d_data->text = text;
+
+ update();
+ updateGeometry();
+}
+
+//! Return the text
+const QwtText &QwtTextLabel::text() const
+{
+ return d_data->text;
+}
+
+//! Clear the text and all QwtText attributes
+void QwtTextLabel::clear()
+{
+ d_data->text = QwtText();
+
+ update();
+ updateGeometry();
+}
+
+//! Return label's text indent in pixels
+int QwtTextLabel::indent() const
+{
+ return d_data->indent;
+}
+
+/*!
+ Set label's text indent in pixels
+ \param indent Indentation in pixels
+*/
+void QwtTextLabel::setIndent( int indent )
+{
+ if ( indent < 0 )
+ indent = 0;
+
+ d_data->indent = indent;
+
+ update();
+ updateGeometry();
+}
+
+//! Return label's text indent in pixels
+int QwtTextLabel::margin() const
+{
+ return d_data->margin;
+}
+
+/*!
+ Set label's margin in pixels
+ \param margin Margin in pixels
+*/
+void QwtTextLabel::setMargin( int margin )
+{
+ d_data->margin = margin;
+
+ update();
+ updateGeometry();
+}
+
+//! Return label's margin in pixels
+QSize QwtTextLabel::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+//! Return a minimum size hint
+QSize QwtTextLabel::minimumSizeHint() const
+{
+ QSizeF sz = d_data->text.textSize( font() );
+
+ int mw = 2 * ( frameWidth() + d_data->margin );
+ int mh = mw;
+
+ int indent = d_data->indent;
+ if ( indent <= 0 )
+ indent = defaultIndent();
+
+ if ( indent > 0 )
+ {
+ const int align = d_data->text.renderFlags();
+ if ( align & Qt::AlignLeft || align & Qt::AlignRight )
+ mw += d_data->indent;
+ else if ( align & Qt::AlignTop || align & Qt::AlignBottom )
+ mh += d_data->indent;
+ }
+
+ sz += QSizeF( mw, mh );
+
+ return QSize( qCeil( sz.width() ), qCeil( sz.height() ) );
+}
+
+/*!
+ \param width Width
+ \return Preferred height for this widget, given the width.
+*/
+int QwtTextLabel::heightForWidth( int width ) const
+{
+ const int renderFlags = d_data->text.renderFlags();
+
+ int indent = d_data->indent;
+ if ( indent <= 0 )
+ indent = defaultIndent();
+
+ width -= 2 * frameWidth();
+ if ( renderFlags & Qt::AlignLeft || renderFlags & Qt::AlignRight )
+ width -= indent;
+
+ int height = qCeil( d_data->text.heightForWidth( width, font() ) );
+ if ( ( renderFlags & Qt::AlignTop ) || ( renderFlags & Qt::AlignBottom ) )
+ height += indent;
+
+ height += 2 * frameWidth();
+
+ return height;
+}
+
+/*!
+ Qt paint event
+ \param event Paint event
+*/
+void QwtTextLabel::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+
+ if ( !contentsRect().contains( event->rect() ) )
+ {
+ painter.save();
+ painter.setClipRegion( event->region() & frameRect() );
+ drawFrame( &painter );
+ painter.restore();
+ }
+
+ painter.setClipRegion( event->region() & contentsRect() );
+
+ drawContents( &painter );
+}
+
+//! Redraw the text and focus indicator
+void QwtTextLabel::drawContents( QPainter *painter )
+{
+ const QRect r = textRect();
+ if ( r.isEmpty() )
+ return;
+
+ painter->setFont( font() );
+ painter->setPen( palette().color( QPalette::Active, QPalette::Text ) );
+
+ drawText( painter, r );
+
+ if ( hasFocus() )
+ {
+ const int margin = 2;
+
+ QRect focusRect = contentsRect();
+ focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin,
+ focusRect.width() - 2 * margin - 2,
+ focusRect.height() - 2 * margin - 2 );
+
+ QwtPainter::drawFocusRect( painter, this, focusRect );
+ }
+}
+
+//! Redraw the text
+void QwtTextLabel::drawText( QPainter *painter, const QRect &textRect )
+{
+ d_data->text.draw( painter, textRect );
+}
+
+/*!
+ Calculate the rect for the text in widget coordinates
+ \return Text rect
+*/
+QRect QwtTextLabel::textRect() const
+{
+ QRect r = contentsRect();
+
+ if ( !r.isEmpty() && d_data->margin > 0 )
+ {
+ r.setRect( r.x() + d_data->margin, r.y() + d_data->margin,
+ r.width() - 2 * d_data->margin, r.height() - 2 * d_data->margin );
+ }
+
+ if ( !r.isEmpty() )
+ {
+ int indent = d_data->indent;
+ if ( indent <= 0 )
+ indent = defaultIndent();
+
+ if ( indent > 0 )
+ {
+ const int renderFlags = d_data->text.renderFlags();
+
+ if ( renderFlags & Qt::AlignLeft )
+ r.setX( r.x() + indent );
+ else if ( renderFlags & Qt::AlignRight )
+ r.setWidth( r.width() - indent );
+ else if ( renderFlags & Qt::AlignTop )
+ r.setY( r.y() + indent );
+ else if ( renderFlags & Qt::AlignBottom )
+ r.setHeight( r.height() - indent );
+ }
+ }
+
+ return r;
+}
+
+int QwtTextLabel::defaultIndent() const
+{
+ if ( frameWidth() <= 0 )
+ return 0;
+
+ QFont fnt;
+ if ( d_data->text.testPaintAttribute( QwtText::PaintUsingTextFont ) )
+ fnt = d_data->text.font();
+ else
+ fnt = font();
+
+ return QFontMetrics( fnt ).width( 'x' ) / 2;
+}
+
diff --git a/src/libpcp_qwt/src/qwt_text_label.h b/src/libpcp_qwt/src/qwt_text_label.h
new file mode 100644
index 0000000..44d3a56
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_text_label.h
@@ -0,0 +1,72 @@
+/* -*- 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_TEXT_LABEL_H
+#define QWT_TEXT_LABEL_H
+
+#include "qwt_global.h"
+#include "qwt_text.h"
+#include <qframe.h>
+
+class QString;
+class QPaintEvent;
+class QPainter;
+
+/*!
+ \brief A Widget which displays a QwtText
+*/
+
+class QWT_EXPORT QwtTextLabel : public QFrame
+{
+ Q_OBJECT
+
+ Q_PROPERTY( int indent READ indent WRITE setIndent )
+ Q_PROPERTY( int margin READ margin WRITE setMargin )
+
+public:
+ explicit QwtTextLabel( QWidget *parent = NULL );
+ explicit QwtTextLabel( const QwtText &, QWidget *parent = NULL );
+ virtual ~QwtTextLabel();
+
+public Q_SLOTS:
+ void setText( const QString &,
+ QwtText::TextFormat textFormat = QwtText::AutoText );
+ virtual void setText( const QwtText & );
+
+ void clear();
+
+public:
+ const QwtText &text() const;
+
+ int indent() const;
+ void setIndent( int );
+
+ int margin() const;
+ void setMargin( int );
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+ virtual int heightForWidth( int ) const;
+
+ QRect textRect() const;
+
+protected:
+ virtual void paintEvent( QPaintEvent *e );
+ virtual void drawContents( QPainter * );
+ virtual void drawText( QPainter *, const QRect & );
+
+private:
+ void init();
+ int defaultIndent() const;
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_thermo.cpp b/src/libpcp_qwt/src/qwt_thermo.cpp
new file mode 100644
index 0000000..6bfa8c4
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_thermo.cpp
@@ -0,0 +1,1036 @@
+/* -*- 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_thermo.h"
+#include "qwt_scale_engine.h"
+#include "qwt_scale_draw.h"
+#include "qwt_scale_map.h"
+#include "qwt_color_map.h"
+#include <qpainter.h>
+#include <qevent.h>
+#include <qdrawutil.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+
+static inline bool qwtIsLogarithmic( const QwtThermo *thermo )
+{
+ const QwtScaleTransformation::Type scaleType =
+ thermo->scaleEngine()->transformation()->type();
+
+ return ( scaleType == QwtScaleTransformation::Log10 );
+}
+
+static inline void qwtDrawLine(
+ QPainter *painter, int pos,
+ const QColor &color, const QRect pipeRect,
+ Qt::Orientation orientation )
+{
+ painter->setPen( color );
+ if ( orientation == Qt::Horizontal )
+ painter->drawLine( pos, pipeRect.top(), pos, pipeRect.bottom() );
+ else
+ painter->drawLine( pipeRect.left(), pos, pipeRect.right(), pos );
+}
+
+QVector<double> qwtTickList( const QwtScaleDiv &scaleDiv, double value )
+{
+ QVector<double> values;
+
+ double lowerLimit = scaleDiv.interval().minValue();
+ double upperLimit = scaleDiv.interval().maxValue();
+
+ if ( upperLimit < lowerLimit )
+ qSwap( lowerLimit, upperLimit );
+
+ if ( value < lowerLimit )
+ return values;
+
+ if ( value < upperLimit )
+ upperLimit = value;
+
+ values += lowerLimit;
+
+ for ( int tickType = QwtScaleDiv::MinorTick;
+ tickType < QwtScaleDiv::NTickTypes; tickType++ )
+ {
+ const QList<double> ticks = scaleDiv.ticks( tickType );
+
+ for ( int i = 0; i < ticks.count(); i++ )
+ {
+ const double v = ticks[i];
+ if ( v > lowerLimit && v < upperLimit )
+ values += v;
+ }
+ }
+
+ values += upperLimit;
+
+ return values;
+}
+
+class QwtThermo::PrivateData
+{
+public:
+ PrivateData():
+ orientation( Qt::Vertical ),
+ scalePos( QwtThermo::LeftScale ),
+ spacing( 3 ),
+ borderWidth( 2 ),
+ pipeWidth( 10 ),
+ minValue( 0.0 ),
+ maxValue( 0.0 ),
+ value( 0.0 ),
+ alarmLevel( 0.0 ),
+ alarmEnabled( false ),
+ autoFillPipe( true ),
+ colorMap( NULL )
+ {
+ rangeFlags = QwtInterval::IncludeBorders;
+ }
+
+ ~PrivateData()
+ {
+ delete colorMap;
+ }
+
+ QwtScaleMap map;
+
+ Qt::Orientation orientation;
+ ScalePos scalePos;
+ int spacing;
+ int borderWidth;
+ int pipeWidth;
+
+ double minValue;
+ double maxValue;
+ QwtInterval::BorderFlags rangeFlags;
+ double value;
+ double alarmLevel;
+ bool alarmEnabled;
+ bool autoFillPipe;
+
+ QwtColorMap *colorMap;
+};
+
+/*!
+ Constructor
+ \param parent Parent widget
+*/
+QwtThermo::QwtThermo( QWidget *parent ):
+ QWidget( parent )
+{
+ d_data = new PrivateData;
+ setRange( 0.0, 1.0, false );
+
+ QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
+ if ( d_data->orientation == Qt::Vertical )
+ policy.transpose();
+
+ setSizePolicy( policy );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+}
+
+//! Destructor
+QwtThermo::~QwtThermo()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Exclude/Include min/max values
+
+ According to the flags minValue() and maxValue()
+ are included/excluded from the pipe. In case of an
+ excluded value the corresponding tick is painted
+ 1 pixel off of the pipeRect().
+
+ F.e. when a minimum
+ of 0.0 has to be displayed as an empty pipe the minValue()
+ needs to be excluded.
+
+ \param flags Range flags
+ \sa rangeFlags()
+*/
+void QwtThermo::setRangeFlags( QwtInterval::BorderFlags flags )
+{
+ if ( d_data->rangeFlags != flags )
+ {
+ d_data->rangeFlags = flags;
+ update();
+ }
+}
+
+/*!
+ \return Range flags
+ \sa setRangeFlags()
+*/
+QwtInterval::BorderFlags QwtThermo::rangeFlags() const
+{
+ return d_data->rangeFlags;
+}
+
+/*!
+ Set the maximum value.
+
+ \param maxValue Maximum value
+ \sa maxValue(), setMinValue(), setRange()
+*/
+void QwtThermo::setMaxValue( double maxValue )
+{
+ setRange( d_data->minValue, maxValue, qwtIsLogarithmic( this ) );
+}
+
+//! Return the maximum value.
+double QwtThermo::maxValue() const
+{
+ return d_data->maxValue;
+}
+
+/*!
+ Set the minimum value.
+
+ \param minValue Minimum value
+ \sa minValue(), setMaxValue(), setRange()
+*/
+void QwtThermo::setMinValue( double minValue )
+{
+ setRange( minValue, d_data->maxValue, qwtIsLogarithmic( this ) );
+}
+
+//! Return the minimum value.
+double QwtThermo::minValue() const
+{
+ return d_data->minValue;
+}
+
+/*!
+ Set the current value.
+
+ \param value New Value
+ \sa value()
+*/
+void QwtThermo::setValue( double value )
+{
+ if ( d_data->value != value )
+ {
+ d_data->value = value;
+ update();
+ }
+}
+
+//! Return the value.
+double QwtThermo::value() const
+{
+ return d_data->value;
+}
+
+/*!
+ \brief Set a scale draw
+
+ For changing the labels of the scales, it
+ is necessary to derive from QwtScaleDraw and
+ overload QwtScaleDraw::label().
+
+ \param scaleDraw ScaleDraw object, that has to be created with
+ new and will be deleted in ~QwtThermo or the next
+ call of setScaleDraw().
+*/
+void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw )
+{
+ setAbstractScaleDraw( scaleDraw );
+}
+
+/*!
+ \return the scale draw of the thermo
+ \sa setScaleDraw()
+*/
+const QwtScaleDraw *QwtThermo::scaleDraw() const
+{
+ return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
+}
+
+/*!
+ \return the scale draw of the thermo
+ \sa setScaleDraw()
+*/
+QwtScaleDraw *QwtThermo::scaleDraw()
+{
+ return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
+}
+
+/*!
+ Qt paint event.
+ \param event Paint event
+*/
+void QwtThermo::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+ painter.setClipRegion( event->region() );
+
+ QStyleOption opt;
+ opt.init(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
+
+ const QRect tRect = pipeRect();
+
+ if ( !tRect.contains( event->rect() ) )
+ {
+ if ( d_data->scalePos != NoScale )
+ scaleDraw()->draw( &painter, palette() );
+ }
+
+ const int bw = d_data->borderWidth;
+
+ const QBrush brush = palette().brush( QPalette::Base );
+ qDrawShadePanel( &painter,
+ tRect.adjusted( -bw, -bw, bw, bw ),
+ palette(), true, bw,
+ d_data->autoFillPipe ? &brush : NULL );
+
+ drawLiquid( &painter, tRect );
+}
+
+/*!
+ Qt resize event handler
+ \param event Resize event
+*/
+void QwtThermo::resizeEvent( QResizeEvent *event )
+{
+ Q_UNUSED( event );
+ layoutThermo( false );
+}
+
+/*!
+ Qt change event handler
+ \param event Event
+*/
+void QwtThermo::changeEvent( QEvent *event )
+{
+ switch( event->type() )
+ {
+ case QEvent::StyleChange:
+ case QEvent::FontChange:
+ {
+ layoutThermo( true );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*!
+ Recalculate the QwtThermo geometry and layout based on
+ the QwtThermo::contentsRect() and the fonts.
+
+ \param update_geometry notify the layout system and call update
+ to redraw the scale
+*/
+void QwtThermo::layoutThermo( bool update_geometry )
+{
+ const QRect tRect = pipeRect();
+ const int bw = d_data->borderWidth + d_data->spacing;
+ const bool inverted = ( maxValue() < minValue() );
+
+ int from, to;
+
+ if ( d_data->orientation == Qt::Horizontal )
+ {
+ from = tRect.left();
+ to = tRect.right();
+
+ if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
+ {
+ if ( inverted )
+ to++;
+ else
+ from--;
+ }
+ if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
+ {
+ if ( inverted )
+ from--;
+ else
+ to++;
+ }
+
+ switch ( d_data->scalePos )
+ {
+ case TopScale:
+ {
+ scaleDraw()->setAlignment( QwtScaleDraw::TopScale );
+ scaleDraw()->move( from, tRect.top() - bw );
+ scaleDraw()->setLength( to - from );
+ break;
+ }
+
+ case BottomScale:
+ case NoScale:
+ default:
+ {
+ scaleDraw()->setAlignment( QwtScaleDraw::BottomScale );
+ scaleDraw()->move( from, tRect.bottom() + bw );
+ scaleDraw()->setLength( to - from );
+ break;
+ }
+ }
+
+ d_data->map.setPaintInterval( from, to );
+ }
+ else // Qt::Vertical
+ {
+ from = tRect.top();
+ to = tRect.bottom();
+
+ if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
+ {
+ if ( inverted )
+ from--;
+ else
+ to++;
+ }
+ if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
+ {
+ if ( inverted )
+ to++;
+ else
+ from--;
+ }
+
+ switch ( d_data->scalePos )
+ {
+ case RightScale:
+ {
+ scaleDraw()->setAlignment( QwtScaleDraw::RightScale );
+ scaleDraw()->move( tRect.right() + bw, from );
+ scaleDraw()->setLength( to - from );
+ break;
+ }
+
+ case LeftScale:
+ case NoScale:
+ default:
+ {
+ scaleDraw()->setAlignment( QwtScaleDraw::LeftScale );
+ scaleDraw()->move( tRect.left() - bw, from );
+ scaleDraw()->setLength( to - from );
+ break;
+ }
+ }
+ d_data->map.setPaintInterval( to, from );
+ }
+
+ if ( update_geometry )
+ {
+ updateGeometry();
+ update();
+ }
+}
+
+/*!
+ \return Bounding rectangle of the pipe ( without borders )
+ in widget coordinates
+*/
+QRect QwtThermo::pipeRect() const
+{
+ const QRect cr = contentsRect();
+
+ int mbd = 0;
+ if ( d_data->scalePos != NoScale )
+ {
+ int d1, d2;
+ scaleDraw()->getBorderDistHint( font(), d1, d2 );
+ mbd = qMax( d1, d2 );
+ }
+ const int bw = d_data->borderWidth;
+
+ QRect tRect;
+ if ( d_data->orientation == Qt::Horizontal )
+ {
+ switch ( d_data->scalePos )
+ {
+ case TopScale:
+ {
+ tRect.setRect(
+ cr.x() + mbd + bw,
+ cr.y() + cr.height() - d_data->pipeWidth - bw,
+ cr.width() - 2 * ( bw + mbd ),
+ d_data->pipeWidth
+ );
+ break;
+ }
+
+ case BottomScale:
+ case NoScale:
+ default:
+ {
+ tRect.setRect(
+ cr.x() + mbd + bw,
+ cr.y() + bw,
+ cr.width() - 2 * ( bw + mbd ),
+ d_data->pipeWidth
+ );
+ break;
+ }
+ }
+ }
+ else // Qt::Vertical
+ {
+ switch ( d_data->scalePos )
+ {
+ case RightScale:
+ {
+ tRect.setRect(
+ cr.x() + bw,
+ cr.y() + mbd + bw,
+ d_data->pipeWidth,
+ cr.height() - 2 * ( bw + mbd )
+ );
+ break;
+ }
+ case LeftScale:
+ case NoScale:
+ default:
+ {
+ tRect.setRect(
+ cr.x() + cr.width() - bw - d_data->pipeWidth,
+ cr.y() + mbd + bw,
+ d_data->pipeWidth,
+ cr.height() - 2 * ( bw + mbd ) );
+ break;
+ }
+ }
+ }
+
+ return tRect;
+}
+
+/*!
+ \brief Set the thermometer orientation and the scale position.
+
+ The scale position NoScale disables the scale.
+ \param o orientation. Possible values are Qt::Horizontal and Qt::Vertical.
+ The default value is Qt::Vertical.
+ \param s Position of the scale.
+ The default value is NoScale.
+
+ A valid combination of scale position and orientation is enforced:
+ - a horizontal thermometer can have the scale positions TopScale,
+ BottomScale or NoScale;
+ - a vertical thermometer can have the scale positions LeftScale,
+ RightScale or NoScale;
+ - an invalid scale position will default to NoScale.
+
+ \sa setScalePosition()
+*/
+void QwtThermo::setOrientation( Qt::Orientation o, ScalePos s )
+{
+ if ( o == d_data->orientation && s == d_data->scalePos )
+ return;
+
+ switch ( o )
+ {
+ case Qt::Horizontal:
+ {
+ if ( ( s == NoScale ) || ( s == BottomScale ) || ( s == TopScale ) )
+ d_data->scalePos = s;
+ else
+ d_data->scalePos = NoScale;
+ break;
+ }
+ case Qt::Vertical:
+ {
+ if ( ( s == NoScale ) || ( s == LeftScale ) || ( s == RightScale ) )
+ d_data->scalePos = s;
+ else
+ d_data->scalePos = NoScale;
+ break;
+ }
+ }
+
+ if ( o != d_data->orientation )
+ {
+ if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
+ {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+ }
+ }
+
+ d_data->orientation = o;
+ layoutThermo( true );
+}
+
+/*!
+ \brief Change the scale position (and thermometer orientation).
+
+ \param scalePos Position of the scale.
+
+ A valid combination of scale position and orientation is enforced:
+ - if the new scale position is LeftScale or RightScale, the
+ scale orientation will become Qt::Vertical;
+ - if the new scale position is BottomScale or TopScale, the scale
+ orientation will become Qt::Horizontal;
+ - if the new scale position is NoScale, the scale orientation
+ will not change.
+
+ \sa setOrientation(), scalePosition()
+*/
+void QwtThermo::setScalePosition( ScalePos scalePos )
+{
+ if ( ( scalePos == BottomScale ) || ( scalePos == TopScale ) )
+ setOrientation( Qt::Horizontal, scalePos );
+ else if ( ( scalePos == LeftScale ) || ( scalePos == RightScale ) )
+ setOrientation( Qt::Vertical, scalePos );
+ else
+ setOrientation( d_data->orientation, NoScale );
+}
+
+/*!
+ Return the scale position.
+ \sa setScalePosition()
+*/
+QwtThermo::ScalePos QwtThermo::scalePosition() const
+{
+ return d_data->scalePos;
+}
+
+//! Notify a scale change.
+void QwtThermo::scaleChange()
+{
+ layoutThermo( true );
+}
+
+/*!
+ Redraw the liquid in thermometer pipe.
+ \param painter Painter
+ \param pipeRect Bounding rectangle of the pipe without borders
+*/
+void QwtThermo::drawLiquid(
+ QPainter *painter, const QRect &pipeRect ) const
+{
+ painter->save();
+ painter->setClipRect( pipeRect, Qt::IntersectClip );
+
+ const bool inverted = ( maxValue() < minValue() );
+ if ( d_data->colorMap != NULL )
+ {
+ QwtInterval interval( d_data->minValue, d_data->maxValue );
+ interval = interval.normalized();
+
+ // Because the positions of the ticks are rounded
+ // we calculate the colors for the rounded tick values
+
+ QVector<double> values = qwtTickList(
+ scaleDraw()->scaleDiv(), d_data->value );
+
+ if ( d_data->map.isInverting() )
+ qSort( values.begin(), values.end(), qGreater<double>() );
+ else
+ qSort( values.begin(), values.end(), qLess<double>() );
+
+ int from;
+ if ( !values.isEmpty() )
+ {
+ from = qRound( d_data->map.transform( values[0] ) );
+ qwtDrawLine( painter, from,
+ d_data->colorMap->color( interval, values[0] ),
+ pipeRect, d_data->orientation );
+ }
+
+ for ( int i = 1; i < values.size(); i++ )
+ {
+ const int to = qRound( d_data->map.transform( values[i] ) );
+
+ for ( int pos = from + 1; pos < to; pos++ )
+ {
+ const double v = d_data->map.invTransform( pos );
+
+ qwtDrawLine( painter, pos,
+ d_data->colorMap->color( interval, v ),
+ pipeRect, d_data->orientation );
+ }
+ qwtDrawLine( painter, to,
+ d_data->colorMap->color( interval, values[i] ),
+ pipeRect, d_data->orientation );
+
+ from = to;
+ }
+ }
+ else
+ {
+ const int tval = qRound( d_data->map.transform( d_data->value ) );
+
+ QRect fillRect = pipeRect;
+ if ( d_data->orientation == Qt::Horizontal )
+ {
+ if ( inverted )
+ fillRect.setLeft( tval );
+ else
+ fillRect.setRight( tval );
+ }
+ else // Qt::Vertical
+ {
+ if ( inverted )
+ fillRect.setBottom( tval );
+ else
+ fillRect.setTop( tval );
+ }
+
+ if ( d_data->alarmEnabled &&
+ d_data->value >= d_data->alarmLevel )
+ {
+ QRect alarmRect = fillRect;
+
+ const int taval = qRound( d_data->map.transform( d_data->alarmLevel ) );
+ if ( d_data->orientation == Qt::Horizontal )
+ {
+ if ( inverted )
+ alarmRect.setRight( taval );
+ else
+ alarmRect.setLeft( taval );
+ }
+ else
+ {
+ if ( inverted )
+ alarmRect.setTop( taval );
+ else
+ alarmRect.setBottom( taval );
+ }
+
+ fillRect = QRegion( fillRect ).subtracted( alarmRect ).boundingRect();
+
+ painter->fillRect( alarmRect, palette().brush( QPalette::Highlight ) );
+ }
+
+ painter->fillRect( fillRect, palette().brush( QPalette::ButtonText ) );
+ }
+
+ painter->restore();
+}
+
+/*!
+ \brief Change the spacing between pipe and scale
+
+ A spacing of 0 means, that the backbone of the scale is below
+ the pipe.
+
+ The default setting is 3 pixels.
+
+ \param spacing Number of pixels
+ \sa spacing();
+*/
+void QwtThermo::setSpacing( int spacing )
+{
+ if ( spacing <= 0 )
+ spacing = 0;
+
+ if ( spacing != d_data->spacing )
+ {
+ d_data->spacing = spacing;
+ layoutThermo( true );
+ }
+}
+
+/*!
+ \return Number of pixels between pipe and scale
+ \sa setSpacing()
+*/
+int QwtThermo::spacing() const
+{
+ return d_data->spacing;
+}
+
+/*!
+ Set the border width of the pipe.
+ \param width Border width
+ \sa borderWidth()
+*/
+void QwtThermo::setBorderWidth( int width )
+{
+ if ( width <= 0 )
+ width = 0;
+
+ if ( width != d_data->borderWidth )
+ {
+ d_data->borderWidth = width;
+ layoutThermo( true );
+ }
+}
+
+/*!
+ Return the border width of the thermometer pipe.
+ \sa setBorderWidth()
+*/
+int QwtThermo::borderWidth() const
+{
+ return d_data->borderWidth;
+}
+
+/*!
+ \brief Set the range
+
+ \param minValue value corresponding lower or left end
+ of the thermometer
+ \param maxValue value corresponding to the upper or
+ right end of the thermometer
+ \param logarithmic logarithmic mapping, true or false
+*/
+void QwtThermo::setRange(
+ double minValue, double maxValue, bool logarithmic )
+{
+ if ( minValue == d_data->minValue && maxValue == d_data->maxValue
+ && logarithmic == qwtIsLogarithmic( this ) )
+ {
+ return;
+ }
+
+ if ( logarithmic != qwtIsLogarithmic( this ) )
+ {
+ if ( logarithmic )
+ setScaleEngine( new QwtLog10ScaleEngine );
+ else
+ setScaleEngine( new QwtLinearScaleEngine );
+ }
+
+ d_data->minValue = minValue;
+ d_data->maxValue = maxValue;
+
+ /*
+ There are two different maps, one for the scale, the other
+ for the values. This is confusing and will be changed
+ in the future. TODO ...
+ */
+
+ d_data->map.setTransformation( scaleEngine()->transformation() );
+ d_data->map.setScaleInterval( minValue, maxValue );
+
+ if ( autoScale() )
+ rescale( minValue, maxValue );
+
+ layoutThermo( true );
+}
+
+/*!
+ \brief Assign a color map for the fill color
+
+ \param colorMap Color map
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+void QwtThermo::setColorMap( QwtColorMap *colorMap )
+{
+ if ( colorMap != d_data->colorMap )
+ {
+ delete d_data->colorMap;
+ d_data->colorMap = colorMap;
+ }
+}
+
+/*!
+ \return Color map for the fill color
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+QwtColorMap *QwtThermo::colorMap()
+{
+ return d_data->colorMap;
+}
+
+/*!
+ \return Color map for the fill color
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+const QwtColorMap *QwtThermo::colorMap() const
+{
+ return d_data->colorMap;
+}
+
+/*!
+ \brief Change the brush of the liquid.
+
+ Changes the QPalette::ButtonText brush of the palette.
+
+ \param brush New brush.
+ \sa fillBrush(), QWidget::setPalette()
+*/
+void QwtThermo::setFillBrush( const QBrush& brush )
+{
+ QPalette pal = palette();
+ pal.setBrush( QPalette::ButtonText, brush );
+ setPalette( pal );
+}
+
+/*!
+ Return the liquid ( QPalette::ButtonText ) brush.
+ \sa setFillBrush(), QWidget::palette()
+*/
+const QBrush& QwtThermo::fillBrush() const
+{
+ return palette().brush( QPalette::ButtonText );
+}
+
+/*!
+ \brief Specify the liquid brush above the alarm threshold
+
+ Changes the QPalette::Highlight brush of the palette.
+
+ \param brush New brush.
+ \sa alarmBrush(), QWidget::setPalette()
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+void QwtThermo::setAlarmBrush( const QBrush& brush )
+{
+ QPalette pal = palette();
+ pal.setBrush( QPalette::Highlight, brush );
+ setPalette( pal );
+}
+
+/*!
+ Return the liquid brush ( QPalette::Highlight ) above the alarm threshold.
+ \sa setAlarmBrush(), QWidget::palette()
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+const QBrush& QwtThermo::alarmBrush() const
+{
+ return palette().brush( QPalette::Highlight );
+}
+
+/*!
+ Specify the alarm threshold.
+
+ \param level Alarm threshold
+ \sa alarmLevel()
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+void QwtThermo::setAlarmLevel( double level )
+{
+ d_data->alarmLevel = level;
+ d_data->alarmEnabled = 1;
+ update();
+}
+
+/*!
+ Return the alarm threshold.
+ \sa setAlarmLevel()
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+double QwtThermo::alarmLevel() const
+{
+ return d_data->alarmLevel;
+}
+
+/*!
+ Change the width of the pipe.
+
+ \param width Width of the pipe
+ \sa pipeWidth()
+*/
+void QwtThermo::setPipeWidth( int width )
+{
+ if ( width > 0 )
+ {
+ d_data->pipeWidth = width;
+ layoutThermo( true );
+ }
+}
+
+/*!
+ Return the width of the pipe.
+ \sa setPipeWidth()
+*/
+int QwtThermo::pipeWidth() const
+{
+ return d_data->pipeWidth;
+}
+
+/*!
+ \brief Enable or disable the alarm threshold
+ \param tf true (disabled) or false (enabled)
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+void QwtThermo::setAlarmEnabled( bool tf )
+{
+ d_data->alarmEnabled = tf;
+ update();
+}
+
+/*!
+ \return True, when the alarm threshold is enabled.
+
+ \warning The alarm threshold has no effect, when
+ a color map has been assigned
+*/
+bool QwtThermo::alarmEnabled() const
+{
+ return d_data->alarmEnabled;
+}
+
+/*!
+ \return the minimum size hint
+ \sa minimumSizeHint()
+*/
+QSize QwtThermo::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+/*!
+ \brief Return a minimum size hint
+ \warning The return value depends on the font and the scale.
+ \sa sizeHint()
+*/
+QSize QwtThermo::minimumSizeHint() const
+{
+ int w = 0, h = 0;
+
+ if ( d_data->scalePos != NoScale )
+ {
+ const int sdExtent = qCeil( scaleDraw()->extent( font() ) );
+ const int sdLength = scaleDraw()->minLength( font() );
+
+ w = sdLength;
+ h = d_data->pipeWidth + sdExtent + d_data->spacing;
+
+ }
+ else // no scale
+ {
+ w = 200;
+ h = d_data->pipeWidth;
+ }
+
+ if ( d_data->orientation == Qt::Vertical )
+ qSwap( w, h );
+
+ w += 2 * d_data->borderWidth;
+ h += 2 * d_data->borderWidth;
+
+ // finally add the margins
+ int left, right, top, bottom;
+ getContentsMargins( &left, &top, &right, &bottom );
+ w += left + right;
+ h += top + bottom;
+
+ return QSize( w, h );
+}
diff --git a/src/libpcp_qwt/src/qwt_thermo.h b/src/libpcp_qwt/src/qwt_thermo.h
new file mode 100644
index 0000000..e43ab12
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_thermo.h
@@ -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_THERMO_H
+#define QWT_THERMO_H
+
+#include "qwt_global.h"
+#include "qwt_abstract_scale.h"
+#include "qwt_interval.h"
+#include <qwidget.h>
+
+class QwtScaleDraw;
+class QwtColorMap;
+
+/*!
+ \brief The Thermometer Widget
+
+ QwtThermo is a widget which displays a value in an interval. It supports:
+ - a horizontal or vertical layout;
+ - a range;
+ - a scale;
+ - an alarm level.
+
+ \image html sysinfo.png
+
+ The fill colors might be calculated from an optional color map
+ If no color map has been assigned QwtThermo uses the
+ following colors/brushes from the widget palette:
+
+ - QPalette::Base
+ Background of the pipe
+ - QPalette::ButtonText
+ Fill brush below the alarm level
+ - QPalette::Highlight
+ Fill brush for the values above the alarm level
+ - QPalette::WindowText
+ For the axis of the scale
+ - QPalette::Text
+ For the labels of the scale
+
+ By default, the scale and range run over the same interval of values.
+ QwtAbstractScale::setScale() changes the interval of the scale and allows
+ easy conversion between physical units.
+
+ The example shows how to make the scale indicate in degrees Fahrenheit and
+ to set the value in degrees Kelvin:
+\code
+#include <qapplication.h>
+#include <qwt_thermo.h>
+
+double Kelvin2Fahrenheit(double kelvin)
+{
+ // see http://en.wikipedia.org/wiki/Kelvin
+ return 1.8*kelvin - 459.67;
+}
+
+int main(int argc, char **argv)
+{
+ const double minKelvin = 0.0;
+ const double maxKelvin = 500.0;
+
+ QApplication a(argc, argv);
+ QwtThermo t;
+ t.setRange(minKelvin, maxKelvin);
+ t.setScale(Kelvin2Fahrenheit(minKelvin), Kelvin2Fahrenheit(maxKelvin));
+ // set the value in Kelvin but the scale displays in Fahrenheit
+ // 273.15 Kelvin = 0 Celsius = 32 Fahrenheit
+ t.setValue(273.15);
+ a.setMainWidget(&t);
+ t.show();
+ return a.exec();
+}
+\endcode
+
+ \todo Improve the support for a logarithmic range and/or scale.
+*/
+class QWT_EXPORT QwtThermo: public QWidget, public QwtAbstractScale
+{
+ Q_OBJECT
+
+ Q_ENUMS( ScalePos )
+
+ Q_PROPERTY( bool alarmEnabled READ alarmEnabled WRITE setAlarmEnabled )
+ Q_PROPERTY( double alarmLevel READ alarmLevel WRITE setAlarmLevel )
+ Q_PROPERTY( ScalePos scalePosition READ scalePosition
+ WRITE setScalePosition )
+ Q_PROPERTY( int spacing READ spacing WRITE setSpacing )
+ Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
+ Q_PROPERTY( double maxValue READ maxValue WRITE setMaxValue )
+ Q_PROPERTY( double minValue READ minValue WRITE setMinValue )
+ Q_PROPERTY( int pipeWidth READ pipeWidth WRITE setPipeWidth )
+ Q_PROPERTY( double value READ value WRITE setValue )
+
+public:
+ /*!
+ Scale position. QwtThermo tries to enforce valid combinations of its
+ orientation and scale position:
+
+ - Qt::Horizonal combines with NoScale, TopScale and BottomScale
+ - Qt::Vertical combines with NoScale, LeftScale and RightScale
+
+ \sa setOrientation(), setScalePosition()
+ */
+ enum ScalePos
+ {
+ //! No scale
+ NoScale,
+
+ //! The scale is left of the pipe
+ LeftScale,
+
+ //! The scale is right of the pipe
+ RightScale,
+
+ //! The scale is above the pipe
+ TopScale,
+
+ //! The scale is below the pipe
+ BottomScale
+ };
+
+ explicit QwtThermo( QWidget *parent = NULL );
+ virtual ~QwtThermo();
+
+ void setOrientation( Qt::Orientation, ScalePos );
+
+ void setScalePosition( ScalePos s );
+ ScalePos scalePosition() const;
+
+ void setSpacing( int );
+ int spacing() const;
+
+ void setBorderWidth( int w );
+ int borderWidth() const;
+
+ void setFillBrush( const QBrush &b );
+ const QBrush &fillBrush() const;
+
+ void setAlarmBrush( const QBrush &b );
+ const QBrush &alarmBrush() const;
+
+ void setAlarmLevel( double v );
+ double alarmLevel() const;
+
+ void setAlarmEnabled( bool tf );
+ bool alarmEnabled() const;
+
+ void setColorMap( QwtColorMap * );
+ QwtColorMap *colorMap();
+ const QwtColorMap *colorMap() const;
+
+ void setPipeWidth( int w );
+ int pipeWidth() const;
+
+ void setRangeFlags( QwtInterval::BorderFlags );
+ QwtInterval::BorderFlags rangeFlags() const;
+
+ void setMaxValue( double v );
+ double maxValue() const;
+
+ void setMinValue( double v );
+ double minValue() const;
+
+ double value() const;
+
+ void setRange( double vmin, double vmax, bool lg = false );
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+ void setScaleDraw( QwtScaleDraw * );
+ const QwtScaleDraw *scaleDraw() const;
+
+public Q_SLOTS:
+ virtual void setValue( double val );
+
+protected:
+ virtual void drawLiquid( QPainter *, const QRect & ) const;
+ virtual void scaleChange();
+
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void changeEvent( QEvent * );
+
+ QwtScaleDraw *scaleDraw();
+
+ QRect pipeRect() const;
+
+private:
+ void layoutThermo( bool );
+
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif
diff --git a/src/libpcp_qwt/src/qwt_wheel.cpp b/src/libpcp_qwt/src/qwt_wheel.cpp
new file mode 100644
index 0000000..1379e18
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_wheel.cpp
@@ -0,0 +1,544 @@
+/* -*- 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_wheel.h"
+#include "qwt_math.h"
+#include "qwt_painter.h"
+#include <qevent.h>
+#include <qdrawutil.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qapplication.h>
+
+#if QT_VERSION < 0x040601
+#define qFastSin(x) ::sin(x)
+#endif
+
+class QwtWheel::PrivateData
+{
+public:
+ PrivateData()
+ {
+ viewAngle = 175.0;
+ totalAngle = 360.0;
+ tickCnt = 10;
+ wheelBorderWidth = 2;
+ borderWidth = 2;
+ wheelWidth = 20;
+ };
+
+ double viewAngle;
+ double totalAngle;
+ int tickCnt;
+ int wheelBorderWidth;
+ int borderWidth;
+ int wheelWidth;
+};
+
+//! Constructor
+QwtWheel::QwtWheel( QWidget *parent ):
+ QwtAbstractSlider( Qt::Horizontal, parent )
+{
+ d_data = new PrivateData;
+
+ setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+ setUpdateTime( 50 );
+}
+
+//! Destructor
+QwtWheel::~QwtWheel()
+{
+ delete d_data;
+}
+
+/*!
+ \brief Adjust the number of grooves in the wheel's surface.
+
+ The number of grooves is limited to 6 <= cnt <= 50.
+ Values outside this range will be clipped.
+ The default value is 10.
+
+ \param cnt Number of grooves per 360 degrees
+ \sa tickCnt()
+*/
+void QwtWheel::setTickCnt( int cnt )
+{
+ d_data->tickCnt = qBound( 6, cnt, 50 );
+ update();
+}
+
+/*!
+ \return Number of grooves in the wheel's surface.
+ \sa setTickCnt()
+*/
+int QwtWheel::tickCnt() const
+{
+ return d_data->tickCnt;
+}
+
+/*!
+ \return mass
+*/
+double QwtWheel::mass() const
+{
+ return QwtAbstractSlider::mass();
+}
+
+/*!
+ \brief Set the wheel border width of the wheel.
+
+ The wheel border must not be smaller than 1
+ and is limited in dependence on the wheel's size.
+ Values outside the allowed range will be clipped.
+
+ The wheel border defaults to 2.
+
+ \param borderWidth Border width
+ \sa internalBorder()
+*/
+void QwtWheel::setWheelBorderWidth( int borderWidth )
+{
+ const int d = qMin( width(), height() ) / 3;
+ borderWidth = qMin( borderWidth, d );
+ d_data->wheelBorderWidth = qMax( borderWidth, 1 );
+ update();
+}
+
+/*!
+ \return Wheel border width
+ \sa setWheelBorderWidth()
+*/
+int QwtWheel::wheelBorderWidth() const
+{
+ return d_data->wheelBorderWidth;
+}
+
+/*!
+ \brief Set the border width
+
+ The border defaults to 2.
+
+ \param width Border width
+ \sa borderWidth()
+*/
+void QwtWheel::setBorderWidth( int width )
+{
+ d_data->borderWidth = qMax( width, 0 );
+ update();
+}
+
+/*!
+ \return Border width
+ \sa setBorderWidth()
+*/
+int QwtWheel::borderWidth() const
+{
+ return d_data->borderWidth;
+}
+
+/*!
+ \return Rectangle of the wheel without the outer border
+*/
+QRect QwtWheel::wheelRect() const
+{
+ const int bw = d_data->borderWidth;
+ return contentsRect().adjusted( bw, bw, -bw, -bw );
+}
+
+/*!
+ \brief Set the total angle which the wheel can be turned.
+
+ One full turn of the wheel corresponds to an angle of
+ 360 degrees. A total angle of n*360 degrees means
+ that the wheel has to be turned n times around its axis
+ to get from the minimum value to the maximum value.
+
+ The default setting of the total angle is 360 degrees.
+
+ \param angle total angle in degrees
+ \sa totalAngle()
+*/
+void QwtWheel::setTotalAngle( double angle )
+{
+ if ( angle < 0.0 )
+ angle = 0.0;
+
+ d_data->totalAngle = angle;
+ update();
+}
+
+/*!
+ \return Total angle which the wheel can be turned.
+ \sa setTotalAngle()
+*/
+double QwtWheel::totalAngle() const
+{
+ return d_data->totalAngle;
+}
+
+/*!
+ \brief Set the wheel's orientation.
+ \param o Orientation. Allowed values are
+ Qt::Horizontal and Qt::Vertical.
+ Defaults to Qt::Horizontal.
+ \sa QwtAbstractSlider::orientation()
+*/
+void QwtWheel::setOrientation( Qt::Orientation o )
+{
+ if ( orientation() == o )
+ return;
+
+ if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
+ {
+ QSizePolicy sp = sizePolicy();
+ sp.transpose();
+ setSizePolicy( sp );
+
+ setAttribute( Qt::WA_WState_OwnSizePolicy, false );
+ }
+
+ QwtAbstractSlider::setOrientation( o );
+ update();
+}
+
+/*!
+ \brief Specify the visible portion of the wheel.
+
+ You may use this function for fine-tuning the appearance of
+ the wheel. The default value is 175 degrees. The value is
+ limited from 10 to 175 degrees.
+
+ \param angle Visible angle in degrees
+ \sa viewAngle(), setTotalAngle()
+*/
+void QwtWheel::setViewAngle( double angle )
+{
+ d_data->viewAngle = qBound( 10.0, angle, 175.0 );
+ update();
+}
+
+/*!
+ \return Visible portion of the wheel
+ \sa setViewAngle(), totalAngle()
+*/
+double QwtWheel::viewAngle() const
+{
+ return d_data->viewAngle;
+}
+
+//! Determine the value corresponding to a specified point
+double QwtWheel::getValue( const QPoint &p )
+{
+ const QRectF rect = wheelRect();
+
+ // The reference position is arbitrary, but the
+ // sign of the offset is important
+ double w, dx;
+ if ( orientation() == Qt::Vertical )
+ {
+ w = rect.height();
+ dx = rect.y() - p.y();
+ }
+ else
+ {
+ w = rect.width();
+ dx = p.x() - rect.x();
+ }
+
+ if ( w == 0.0 )
+ return 0.0;
+
+ // w pixels is an arc of viewAngle degrees,
+ // so we convert change in pixels to change in angle
+ const double ang = dx * d_data->viewAngle / w;
+
+ // value range maps to totalAngle degrees,
+ // so convert the change in angle to a change in value
+ const double val = ang * ( maxValue() - minValue() ) / d_data->totalAngle;
+
+ // Note, range clamping and rasterizing to step is automatically
+ // handled by QwtAbstractSlider, so we simply return the change in value
+ return val;
+}
+
+/*!
+ \brief Qt Resize Event
+ \param event Resize event
+*/
+void QwtWheel::resizeEvent( QResizeEvent *event )
+{
+ QwtAbstractSlider::resizeEvent( event );
+}
+
+/*!
+ \brief Qt Paint Event
+ \param event Paint event
+*/
+void QwtWheel::paintEvent( QPaintEvent *event )
+{
+ QPainter painter( this );
+ painter.setClipRegion( event->region() );
+
+ QStyleOption opt;
+ opt.init(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
+
+ qDrawShadePanel( &painter,
+ contentsRect(), palette(), true, d_data->borderWidth );
+
+ drawWheelBackground( &painter, wheelRect() );
+ drawTicks( &painter, wheelRect() );
+
+ if ( hasFocus() )
+ QwtPainter::drawFocusRect( &painter, this );
+}
+
+/*!
+ Draw the Wheel's background gradient
+
+ \param painter Painter
+ \param rect Rectangle for the wheel
+*/
+void QwtWheel::drawWheelBackground(
+ QPainter *painter, const QRectF &rect )
+{
+ painter->save();
+
+ QPalette pal = palette();
+
+ // draw shaded background
+ QLinearGradient gradient( rect.topLeft(),
+ ( orientation() == Qt::Horizontal ) ? rect.topRight() : rect.bottomLeft() );
+ gradient.setColorAt( 0.0, pal.color( QPalette::Button ) );
+ gradient.setColorAt( 0.2, pal.color( QPalette::Light ) );
+ gradient.setColorAt( 0.7, pal.color( QPalette::Mid ) );
+ gradient.setColorAt( 1.0, pal.color( QPalette::Dark ) );
+
+ painter->fillRect( rect, gradient );
+
+ // draw internal border
+
+ const QPen lightPen( palette().color( QPalette::Light ),
+ d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
+ const QPen darkPen( pal.color( QPalette::Dark ),
+ d_data->wheelBorderWidth, Qt::SolidLine, Qt::FlatCap );
+
+ const double bw2 = 0.5 * d_data->wheelBorderWidth;
+
+ if ( orientation() == Qt::Horizontal )
+ {
+ painter->setPen( lightPen );
+ painter->drawLine( QPointF( rect.left(), rect.top() + bw2 ),
+ QPointF( rect.right(), rect.top() + bw2 ) );
+
+ painter->setPen( darkPen );
+ painter->drawLine( QPointF( rect.left(), rect.bottom() - bw2 ),
+ QPointF( rect.right(), rect.bottom() - bw2 ) );
+ }
+ else // Qt::Vertical
+ {
+ painter->setPen( lightPen );
+ painter->drawLine( QPointF( rect.left() + bw2, rect.top() ),
+ QPointF( rect.left() + bw2, rect.bottom() ) );
+
+ painter->setPen( darkPen );
+ painter->drawLine( QPointF( rect.right() - bw2, rect.top() ),
+ QPointF( rect.right() - bw2, rect.bottom() ) );
+ }
+
+ painter->restore();
+}
+
+/*!
+ Draw the Wheel's ticks
+
+ \param painter Painter
+ \param rect Rectangle for the wheel
+*/
+void QwtWheel::drawTicks( QPainter *painter, const QRectF &rect )
+{
+ if ( maxValue() == minValue() || d_data->totalAngle == 0.0 )
+ {
+ return;
+ }
+
+ const QPen lightPen( palette().color( QPalette::Light ),
+ 0, Qt::SolidLine, Qt::FlatCap );
+ const QPen darkPen( palette().color( QPalette::Dark ),
+ 0, Qt::SolidLine, Qt::FlatCap );
+
+ const double sign = ( minValue() < maxValue() ) ? 1.0 : -1.0;
+ const double cnvFactor = qAbs( d_data->totalAngle / ( maxValue() - minValue() ) );
+ const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor;
+ const double loValue = value() - halfIntv;
+ const double hiValue = value() + halfIntv;
+ const double tickWidth = 360.0 / double( d_data->tickCnt ) / cnvFactor;
+ const double sinArc = qFastSin( d_data->viewAngle * M_PI / 360.0 );
+
+ if ( orientation() == Qt::Horizontal )
+ {
+ const double halfSize = rect.width() * 0.5;
+
+ double l1 = rect.top() + d_data->wheelBorderWidth;
+ double l2 = rect.bottom() - d_data->wheelBorderWidth - 1;
+
+ // draw one point over the border if border > 1
+ if ( d_data->wheelBorderWidth > 1 )
+ {
+ l1--;
+ l2++;
+ }
+
+ const double maxpos = rect.right() - 2;
+ const double minpos = rect.left() + 2;
+
+ // draw tick marks
+ for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth;
+ tickValue < hiValue; tickValue += tickWidth )
+ {
+ const double angle = ( tickValue - value() ) * M_PI / 180.0;
+ const double s = qFastSin( angle * cnvFactor );
+
+ const double tickPos =
+ rect.right() - halfSize * ( sinArc + sign * s ) / sinArc;
+
+ if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
+ {
+ painter->setPen( darkPen );
+ painter->drawLine( QPointF( tickPos - 1 , l1 ),
+ QPointF( tickPos - 1, l2 ) );
+ painter->setPen( lightPen );
+ painter->drawLine( QPointF( tickPos, l1 ),
+ QPointF( tickPos, l2 ) );
+ }
+ }
+ }
+ else // Qt::Vertical
+ {
+ const double halfSize = rect.height() * 0.5;
+
+ double l1 = rect.left() + d_data->wheelBorderWidth;
+ double l2 = rect.right() - d_data->wheelBorderWidth - 1;
+
+ if ( d_data->wheelBorderWidth > 1 )
+ {
+ l1--;
+ l2++;
+ }
+
+ const double maxpos = rect.bottom() - 2;
+ const double minpos = rect.top() + 2;
+
+ for ( double tickValue = ::ceil( loValue / tickWidth ) * tickWidth;
+ tickValue < hiValue; tickValue += tickWidth )
+ {
+ const double angle = ( tickValue - value() ) * M_PI / 180.0;
+ const double s = qFastSin( angle * cnvFactor );
+
+ const double tickPos =
+ rect.y() + halfSize * ( sinArc + sign * s ) / sinArc;
+
+ if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
+ {
+ painter->setPen( darkPen );
+ painter->drawLine( QPointF( l1, tickPos - 1 ),
+ QPointF( l2, tickPos - 1 ) );
+ painter->setPen( lightPen );
+ painter->drawLine( QPointF( l1, tickPos ),
+ QPointF( l2, tickPos ) );
+ }
+ }
+ }
+}
+
+//! Notify value change
+void QwtWheel::valueChange()
+{
+ QwtAbstractSlider::valueChange();
+ update();
+}
+
+/*!
+ \brief Determine the scrolling mode and direction corresponding
+ to a specified point
+ \param p point
+ \param scrollMode scrolling mode
+ \param direction direction
+*/
+void QwtWheel::getScrollMode( const QPoint &p,
+ QwtAbstractSlider::ScrollMode &scrollMode, int &direction ) const
+{
+ if ( wheelRect().contains( p ) )
+ scrollMode = QwtAbstractSlider::ScrMouse;
+ else
+ scrollMode = QwtAbstractSlider::ScrNone;
+
+ direction = 0;
+}
+
+/*!
+ \brief Set the mass of the wheel
+
+ Assigning a mass turns the wheel into a flywheel.
+ \param mass The wheel's mass
+*/
+void QwtWheel::setMass( double mass )
+{
+ QwtAbstractSlider::setMass( mass );
+}
+
+/*!
+ \brief Set the width of the wheel
+
+ Corresponds to the wheel height for horizontal orientation,
+ and the wheel width for vertical orientation.
+
+ \param width the wheel's width
+ \sa wheelWidth()
+*/
+void QwtWheel::setWheelWidth( int width )
+{
+ d_data->wheelWidth = width;
+ update();
+}
+
+/*!
+ \return Width of the wheel
+ \sa setWheelWidth()
+*/
+int QwtWheel::wheelWidth() const
+{
+ return d_data->wheelWidth;
+}
+
+/*!
+ \return a size hint
+*/
+QSize QwtWheel::sizeHint() const
+{
+ const QSize hint = minimumSizeHint();
+ return hint.expandedTo( QApplication::globalStrut() );
+}
+
+/*!
+ \brief Return a minimum size hint
+ \warning The return value is based on the wheel width.
+*/
+QSize QwtWheel::minimumSizeHint() const
+{
+ QSize sz( 3 * d_data->wheelWidth + 2 * d_data->borderWidth,
+ d_data->wheelWidth + 2 * d_data->borderWidth );
+ if ( orientation() != Qt::Horizontal )
+ sz.transpose();
+
+ return sz;
+}
diff --git a/src/libpcp_qwt/src/qwt_wheel.h b/src/libpcp_qwt/src/qwt_wheel.h
new file mode 100644
index 0000000..7e18e46
--- /dev/null
+++ b/src/libpcp_qwt/src/qwt_wheel.h
@@ -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_WHEEL_H
+#define QWT_WHEEL_H
+
+#include "qwt_global.h"
+#include "qwt_abstract_slider.h"
+
+/*!
+ \brief The Wheel Widget
+
+ The wheel widget can be used to change values over a very large range
+ in very small steps. Using the setMass member, it can be configured
+ as a flywheel.
+
+ \sa The radio example.
+*/
+class QWT_EXPORT QwtWheel : public QwtAbstractSlider
+{
+ Q_OBJECT
+
+ Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle )
+ Q_PROPERTY( double viewAngle READ viewAngle WRITE setViewAngle )
+ Q_PROPERTY( int tickCnt READ tickCnt WRITE setTickCnt )
+ Q_PROPERTY( int wheelWidth READ wheelWidth WRITE setWheelWidth )
+ Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
+ Q_PROPERTY( int wheelBorderWidth READ wheelBorderWidth WRITE setWheelBorderWidth )
+ Q_PROPERTY( double mass READ mass WRITE setMass )
+
+public:
+ explicit QwtWheel( QWidget *parent = NULL );
+ virtual ~QwtWheel();
+
+public Q_SLOTS:
+ void setTotalAngle ( double );
+ void setViewAngle( double );
+
+public:
+ virtual void setOrientation( Qt::Orientation );
+
+ double totalAngle() const;
+ double viewAngle() const;
+
+ void setTickCnt( int );
+ int tickCnt() const;
+
+ void setMass( double );
+ double mass() const;
+
+ void setWheelWidth( int );
+ int wheelWidth() const;
+
+ void setWheelBorderWidth( int );
+ int wheelBorderWidth() const;
+
+ void setBorderWidth( int );
+ int borderWidth() const;
+
+ QRect wheelRect() const;
+
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ virtual void drawTicks( QPainter *, const QRectF & );
+ virtual void drawWheelBackground( QPainter *, const QRectF & );
+
+ virtual void valueChange();
+
+ virtual double getValue( const QPoint & );
+ virtual void getScrollMode( const QPoint &,
+ QwtAbstractSlider::ScrollMode &, int &direction ) const;
+
+private:
+ class PrivateData;
+ PrivateData *d_data;
+};
+
+#endif