-
Notifications
You must be signed in to change notification settings - Fork 3
/
qcpl_plot.h
229 lines (191 loc) · 10.4 KB
/
qcpl_plot.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#ifndef QCPL_PLOT_H
#define QCPL_PLOT_H
#include "qcpl_types.h"
#include "qcustomplot/qcustomplot.h"
namespace QCPL {
typedef QCPGraph Graph;
class TextFormatterBase;
class FormatSaver;
struct LayoutCell
{
int row;
int col;
};
struct PlotOptions
{
/// Re-create default axes as instances of QCPL::Axis
/// which provides ability to highlight axes in multi-axis scenario
bool replaceDefaultAxes = false;
};
class Plot : public QCustomPlot
{
Q_OBJECT
public:
explicit Plot(const PlotOptions& opts = PlotOptions(), QWidget* parent = nullptr);
~Plot();
QVector<Graph*>& serviceGraphs() { return _serviceGraphs; }
Graph* selectedGraph() const;
enum GraphCountFlags {COUNT_DEFAULT = 0x0, COUNT_ONLY_VISIBLE = 0x1, COUNT_SERVICE = 0x2};
int graphsCount(GraphCountFlags flags = COUNT_DEFAULT) const;
bool graphAutoColors = true;
bool useSafeMargins = true;
bool excludeServiceGraphsFromAutolimiting = true;
bool formatAxisTitleAfterFactorSet = false;
bool highlightAxesOfSelectedGraphs = false;
/// Used for saving format settings of plot elements that can be used as 'default' setting.
/// It is up to application when to load these stored default settings.
QSharedPointer<FormatSaver> formatSaver;
// Plot doesn't take ownership on context menus
QMenu *menuAxisX = nullptr;
QMenu *menuAxisY = nullptr;
QMenu *menuAxis = nullptr;
QMenu *menuGraph = nullptr;
QMenu *menuPlot = nullptr;
QMenu *menuLegend = nullptr;
QMenu *menuTitle = nullptr;
QMap<QCPLayerable*, QMenu*> menus;
QCPAxis *axisUnderMenu;
/// Display axis identifiers used for automatcally shown dialogs.
/// E.g. plot shows limits dialog when an axis is double clicked,
/// and the dialog should have some title. It tries to take a title from this map first
/// and substitutes some default title if nothing has been found. @see axisIdent()
QMap<QCPAxis*, QString> axisIdents;
/// Map of objects with their store keys
/// By default plot consists of axes, title, and legend.
/// Additional parts (e.g. color scale of 2D graph) can be mentioned here
/// in order not to loose them during copy/pasting or format saving.
QHash<QCPLayerable*, QString> additionalParts;
/// The callback used to get axis units for showing in the axis limits dialog.
std::function<QString(QCPAxis*)> getAxisUnitString;
Graph* makeNewGraph(const QString &title);
Graph* makeNewGraph(const QString &title, const GraphData &data, bool replot = true);
void updateGraph(Graph* graph, const GraphData &data, bool replot = true);
/// Returns plot title. The plot has one predefined default title object.
QCPTextElement* title() { return _title; }
/// Puts the visible title into the main plot, and removes it from there if it's hidden.
/// This is because QCustomPlot can't caclulate layout row height properly when an element is not visible.
/// Even when the title is not visible, its height is accounted and layout row height ajusted accordingly.
/// So we see an empty space above the plot instead of non visible title.
/// This is undesired behaviour, so we need to remove the title from the main layout when it's hidden.
void updateTitleVisibility();
AxisLimits limitsX() const { return limits(xAxis); }
AxisLimits limitsY() const { return limits(yAxis); }
AxisLimits limits(QCPAxis* axis) const;
void setLimitsX(const AxisLimits& p, bool replot) { setLimitsX(p.min, p.max, replot); }
void setLimitsY(const AxisLimits& p, bool replot) { setLimitsY(p.min, p.max, replot); }
void setLimitsX(double min, double max, bool replot = true) { setLimits(xAxis, min, max, replot); }
void setLimitsY(double min, double max, bool replot = true) { setLimits(yAxis, min, max, replot); }
void setLimits(QCPAxis* axis, const AxisLimits& p, bool replot) { setLimits(axis, p.min, p.max, replot); }
void setLimits(QCPAxis* axis, double min, double max, bool replot);
void extendLimits(QCPAxis* axis, double factor, bool replot);
void extendLimits(double factor, bool replot = true) { extendLimits(xAxis, factor, false); extendLimits(yAxis, factor, replot); }
void extendLimitsX(double factor, bool replot = true) { extendLimits(xAxis, factor, replot); }
void extendLimitsY(double factor, bool replot = true) { extendLimits(yAxis, factor, replot); }
AxisFactor axisFactor(QCPAxis* axis) const;
AxisFactor axisFactorX() const { return axisFactor(xAxis); }
AxisFactor axisFactorY() const { return axisFactor(yAxis); }
void setAxisFactorX(const AxisFactor& factor) { setAxisFactor(xAxis, factor); }
void setAxisFactorY(const AxisFactor& factor) { setAxisFactor(yAxis, factor); }
void setAxisFactor(QCPAxis* axis, const AxisFactor& factor);
/// Initial layout row and column where the axis rect is placed.
/// It's the row 1 because the row 0 is occupied by the plot title.
/// Can be used for calculation of placement of additional elements, e.g. color scale of 2D plots.
constexpr LayoutCell axisRectRC() const { return { 1, 0}; }
/// Layout row and column when the title is placed.
constexpr LayoutCell titleRC() const { return { 0, 0 }; }
void addTextVar(void* target, const QString& name, const QString& descr, TextVarGetter getter);
void addTextVarT(const QString& name, const QString& descr, TextVarGetter getter) { addTextVar(_title, name, descr, getter); }
void addTextVarX(const QString& name, const QString& descr, TextVarGetter getter) { addTextVar(xAxis, name, descr, getter); }
void addTextVarY(const QString& name, const QString& descr, TextVarGetter getter) { addTextVar(yAxis, name, descr, getter); }
void addFormatter(void* target, TextFormatterBase* formatter);
TextFormatterBase* formatter(void* target) const { return _formatters.contains(target) ? _formatters[target] : nullptr; }
void setFormatterText(void* target, const QString& text);
void setFormatterTextT(const QString& text) { setFormatterText(_title, text); }
void setFormatterTextX(const QString& text) { setFormatterText(xAxis, text); }
void setFormatterTextY(const QString& text) { setFormatterText(yAxis, text); }
QString formatterText(void* target) const;
QString formatterTextT() const { return formatterText(_title); }
QString formatterTextX() const { return formatterText(xAxis); }
QString formatterTextY() const { return formatterText(yAxis); }
void updateTexts();
void updateText(void* target);
void updateTextT() { updateText(_title); }
void updateTextX() { updateText(yAxis); }
void updateTextY() { updateText(xAxis); }
QString defaultText(void* target) const { return _defaultTexts.contains(target) ? _defaultTexts[target] : QString(); }
QString defaultTextT() const { return defaultText(_title); }
QString defaultTextX() const { return defaultText(xAxis); }
QString defaultTextY() const { return defaultText(yAxis); }
void setDefaultText(void* target, const QString& text) { _defaultTexts[target] = text; }
void setDefaultTextT(const QString& text) { setDefaultText(_title, text); }
void setDefaultTextX(const QString& text) { setDefaultText(xAxis, text); }
void setDefaultTextY(const QString& text) { setDefaultText(yAxis, text); }
bool limitsDlg(QCPAxis* axis);
bool axisFactorDlg(QCPAxis* axis);
bool axisTextDlg(QCPAxis* axis);
bool axisFormatDlg(QCPAxis* axis);
bool colorScaleFormatDlg(QCPColorScale* axis);
void autolimits(QCPAxis* axis, bool replot);
QString axisIdent(QCPAxis* axis) const;
QCPAxis* addAxis(QCPAxis::AxisType axisType);
QCPAxis* selectedAxis() const;
QVector<QCPAxis*> defaultAxes() { return {xAxis, yAxis, xAxis2, yAxis2}; }
public slots:
void autolimits(bool replot = true) { autolimits(xAxis, false); autolimits(yAxis, replot); }
void autolimitsX(bool replot = true) { autolimits(xAxis, replot); }
void autolimitsY(bool replot = true) { autolimits(yAxis, replot); }
bool limitsDlgX() { return limitsDlg(xAxis); }
bool limitsDlgY() { return limitsDlg(yAxis); }
bool limitsDlgXY();
bool axisFactorDlgX() { return axisFactorDlg(xAxis); }
bool axisFactorDlgY() { return axisFactorDlg(yAxis); }
void zoomIn() { extendLimits(-(_zoomStepX+_zoomStepY)/2.0); }
void zoomOut() { extendLimits((_zoomStepX+_zoomStepY)/2.0); }
void zoomInX() { extendLimitsX(-_zoomStepX); }
void zoomOutX() { extendLimitsX(_zoomStepX); }
void zoomInY() { extendLimitsY(-_zoomStepY); }
void zoomOutY() { extendLimitsY(_zoomStepY); }
void copyPlotImage();
bool axisTextDlgX() { return axisTextDlg(xAxis); }
bool axisTextDlgY() { return axisTextDlg(yAxis); }
bool axisFormatDlgX() { return axisFormatDlg(xAxis); }
bool axisFormatDlgY() { return axisFormatDlg(yAxis); }
bool titleTextDlg();
bool titleFormatDlg();
bool legendFormatDlg();
signals:
void graphClicked(Graph*);
void emptySpaceDoubleClicked(QMouseEvent *event);
void resized(const QSize& oldSize, const QSize& newSize);
void modified(const QString& reason);
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private slots:
void plotSelectionChanged();
void rawGraphClicked(QCPAbstractPlottable*);
void axisDoubleClicked(QCPAxis*, QCPAxis::SelectablePart);
private:
QVector<Graph*> _serviceGraphs;
QCP::SelectionType _selectionType = QCP::stWhole;
QCPTextElement *_title;
int _nextColorIndex = 0;
const double _safeMarginsX;
const double _safeMarginsY;
const double _zoomStepX;
const double _zoomStepY;
const int _numberPrecision;
QMap<void*, TextFormatterBase*> _formatters;
QMap<void*, QString> _defaultTexts;
QCPLayoutGrid *_backupLayout;
bool isService(Graph* g) const { return _serviceGraphs.contains(g); }
QColor nextGraphColor();
void initDefault(QCPAxis* axis);
void setAxisRange(QCPAxis* axis, const QCPRange &range);
double safeMargins(QCPAxis* axis);
QMenu* findContextMenu(const QPointF& pos);
QString axisTypeStr(QCPAxis::AxisType type) const;
};
} // namespace QCPL
#endif // QCPL_PLOT_H