1 /***************************************************************************
2 * *
3 * copyright : (C) 2007 The University of Toronto *
4 * netterfield@astro.utoronto.ca *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 ***************************************************************************/
12
13 #include "plotitem.h"
14
15 #include "plotitemmanager.h"
16 #include "plotrenderitem.h"
17
18 #include "image.h"
19
20 #include "layoutboxitem.h"
21 #include "viewgridlayout.h"
22 #include "debug.h"
23
24 #include "application.h"
25 #include "mainwindow.h"
26 #include "document.h"
27 #include "tabwidget.h"
28 #include "labelrenderer.h"
29
30 #include "datacollection.h"
31 #include "cartesianrenderitem.h"
32
33 #include "plotitemdialog.h"
34 #include "dialoglauncher.h"
35 #include "sharedaxisboxitem.h"
36
37 #include "applicationsettings.h"
38 #include "updatemanager.h"
39 #include "plotscriptinterface.h"
40 #include "math_kst.h"
41
42 #include "dialogdefaults.h"
43
44 #include <QMenu>
45 #include <QDebug>
46 #include <QGraphicsSceneMouseEvent>
47 #include <QClipboard>
48
49 // Benchmark drawing
50 // undefined = None, 1 = PlotItem, 2 = More Details
51 //#define BENCHMARK 1
52
53 static const int PLOT_MAXIMIZED_ZORDER = 1000;
54
55 namespace Kst {
56
PlotItem(View * parent)57 PlotItem::PlotItem(View *parent)
58 : ViewItem(parent), PlotItemInterface(),
59 _isInSharedAxisBox(false),
60 _manuallyHideLeftAxisLabel(false),
61 _manuallyHideRightAxisLabel(false),
62 _manuallyHideTopAxisLabel(false),
63 _manuallyHideBottomAxisLabel(false),
64 _plotRectsDirty(true),
65 _calculatedLeftLabelMargin(0.0),
66 _calculatedLeftLabelWidth(0.0),
67 _calculatedLeftBaseOffset(0.0),
68 _calculatedRightLabelMargin(0.0),
69 _calculatedTopLabelMargin(0.0),
70 _calculatedTopLabelHeight(0.0),
71 _calculatedBottomLabelMargin(0.0),
72 _calculatedBottomLabelWidth(0.0),
73 _calculatedLabelMarginWidth(0.0),
74 _calculatedLabelMarginHeight(0.0),
75 _calculatedAxisMarginWidth(0.0),
76 _calculatedAxisMarginHeight(0.0),
77 _calculatedAxisMarginVLead(0.0),
78 _calculatedAxisMarginHLead(0.0),
79 _calculatedAxisMarginROverflow(0.0),
80 _calculatedAxisMarginTOverflow(0.0),
81 _leftPadding(0.0),
82 _bottomPadding(0.0),
83 _rightPadding(0.0),
84 _topPadding(0.0),
85 _globalFontScale(14.0),
86 _numberAxisLabelScaleFactor(1.0),
87 _useNumberAxisLabelScale(true),
88 _showLegend(false),
89 _allowUpdates(true),
90 _legend(0),
91 _zoomMenu(0),
92 _filterMenu(0),
93 _fitMenu(0),
94 _psdMenu(0),
95 _histogramMenu(0),
96 _editMenu(0),
97 _sharedAxisBoxMenu(0),
98 _copyMenu(0),
99 _sharedBox(0),
100 _axisLabelsDirty(true),
101
102 _plotPixmapDirty(true),
103 _i_per(0)
104 {
105 setTypeName(tr("Plot", "a plot of data"));
106 _initializeShortName();
107
108 setBrush(Qt::white);
109
110 setSupportsTiedZoom(true);
111
112 _xAxis = new PlotAxis(this, Qt::Horizontal);
113 _yAxis = new PlotAxis(this, Qt::Vertical);
114
115 connect(this, SIGNAL(geometryChanged()), _xAxis, SLOT(setTicksUpdated()));
116 connect(this, SIGNAL(geometryChanged()), _yAxis, SLOT(setTicksUpdated()));
117 connect(this, SIGNAL(geometryChanged()), this, SLOT(setPlotRectsDirty()));
118
119 _leftLabelDetails = new PlotLabel(this);
120 _rightLabelDetails = new PlotLabel(this);
121 _topLabelDetails = new PlotLabel(this);
122 _bottomLabelDetails = new PlotLabel(this);
123 _numberLabelDetails = new PlotLabel(this);
124
125 //view()->configurePlotFontDefaults(this);
126
127 connect(_leftLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
128 connect(_leftLabelDetails, SIGNAL(labelChanged()), this, SLOT(setLeftLabelDirty()));
129 connect(_rightLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
130 connect(_rightLabelDetails, SIGNAL(labelChanged()), this, SLOT(setRightLabelDirty()));
131 connect(_topLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
132 connect(_topLabelDetails, SIGNAL(labelChanged()), this, SLOT(setTopLabelDirty()));
133 connect(_bottomLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
134 connect(_bottomLabelDetails, SIGNAL(labelChanged()), this, SLOT(setBottomLabelDirty()));
135 connect(_numberLabelDetails, SIGNAL(labelChanged()), this, SLOT(setPlotBordersDirty()));
136 connect(_numberLabelDetails, SIGNAL(labelChanged()), this, SLOT(setAxisLabelsDirty()));
137
138 _undoStack = new QUndoStack(this);
139
140 createActions();
141
142 // Set the initial projection.
143 setProjectionRect(QRectF(QPointF(-0.1, -0.1), QPointF(0.1, 0.1)));
144 renderItem(PlotRenderItem::Cartesian);
145
146 setPlotBordersDirty(true);
147 connect(this, SIGNAL(triggerRedraw()), this, SLOT(redrawPlot()));
148 connect(this, SIGNAL(geometryChanged()), this, SLOT(setLabelsDirty()));
149 connect(this, SIGNAL(updateAxes()), this, SLOT(setPlotPixmapDirty()));
150 connect(this, SIGNAL(geometryChanged()), this, SLOT(setPlotPixmapDirty()));
151
152 applyDefaults();
153 applyDialogDefaultsStroke();
154 applyDialogDefaultsFill();
155 applyDialogDefaultsLockPosToData();
156 }
157
createScriptInterface()158 ScriptInterface* PlotItem::createScriptInterface() {
159 return new PlotSI(this);
160 }
161
162
applyDefaults()163 void PlotItem::applyDefaults() {
164 QFont font;
165
166 // Global Font Settings
167 QFont globalfont;
168 globalfont.fromString(dialogDefaults().value(defaultsGroupName()+"/globalFontFamily",globalfont.toString()).toString());
169 setGlobalFont(globalfont);
170 setGlobalFontScale(dialogDefaults().value(defaultsGroupName()+"/globalFontScale", 13).toDouble());
171 QColor color;
172 color = dialogDefaults().value(defaultsGroupName()+"/globalFontColor", QColor(Qt::black)).value<QColor>();
173 setGlobalFontColor(color);
174
175 // Left Font Settings
176 leftLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/leftFontGlobal", true).toBool());
177 font.fromString(dialogDefaults().value(defaultsGroupName()+"/leftFontFamily",globalfont.toString()).toString());
178 leftLabelDetails()->setFont(font);
179 leftLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/leftFontScale", 13).toDouble());
180 color = dialogDefaults().value(defaultsGroupName()+"/leftFontColor", QColor(Qt::black)).value<QColor>();
181 leftLabelDetails()->setFontColor(color);
182
183 // right Font Settings
184 rightLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/rightFontGlobal", true).toBool());
185 font.fromString(dialogDefaults().value(defaultsGroupName()+"/rightFontFamily",globalfont.toString()).toString());
186 rightLabelDetails()->setFont(font);
187 rightLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/rightFontScale", 13).toDouble());
188 color = dialogDefaults().value(defaultsGroupName()+"/rightFontColor", QColor(Qt::black)).value<QColor>();
189 rightLabelDetails()->setFontColor(color);
190
191 // top Font Settings
192 topLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/topFontGlobal", true).toBool());
193 font.fromString(dialogDefaults().value(defaultsGroupName()+"/topFontFamily",globalfont.toString()).toString());
194 topLabelDetails()->setFont(font);
195 topLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/topFontScale", 13).toDouble());
196 color = dialogDefaults().value(defaultsGroupName()+"/topFontColor", QColor(Qt::black)).value<QColor>();
197 topLabelDetails()->setFontColor(color);
198
199 // bottom Font Settings
200 bottomLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/bottomFontGlobal", true).toBool());
201 font.fromString(dialogDefaults().value(defaultsGroupName()+"/bottomFontFamily",globalfont.toString()).toString());
202 bottomLabelDetails()->setFont(font);
203 bottomLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/bottomFontScale", 13).toDouble());
204 color = dialogDefaults().value(defaultsGroupName()+"/bottomFontColor", QColor(Qt::black)).value<QColor>();
205 bottomLabelDetails()->setFontColor(color);
206
207 // number Font Settings
208 numberLabelDetails()->setFontUseGlobal(dialogDefaults().value(defaultsGroupName()+"/numberFontGlobal", true).toBool());
209 font.fromString(dialogDefaults().value(defaultsGroupName()+"/numberFontFamily",globalfont.toString()).toString());
210 numberLabelDetails()->setFont(font);
211 numberLabelDetails()->setFontScale(dialogDefaults().value(defaultsGroupName()+"/numberFontScale", 13).toDouble());
212 color = dialogDefaults().value(defaultsGroupName()+"/numberFontColor", QColor(Qt::black)).value<QColor>();
213 numberLabelDetails()->setFontColor(color);
214
215 xAxis()->setAxisVisible(dialogDefaults().value(defaultsGroupName()+"/xAxisVisible", true).toBool());
216 xAxis()->setAxisLog(dialogDefaults().value(defaultsGroupName()+"/xAxisLog", false).toBool());
217 xAxis()->setAxisReversed(dialogDefaults().value(defaultsGroupName()+"/xAxisReversed", false).toBool());
218 xAxis()->setAxisAutoBaseOffset(dialogDefaults().value(defaultsGroupName()+"/xAxisAutoBaseOffset", true).toBool());
219 xAxis()->setAxisBaseOffset(dialogDefaults().value(defaultsGroupName()+"/xAxisBaseOffset", false).toBool());
220 xAxis()->setAxisForceOffsetMin(dialogDefaults().value(defaultsGroupName()+"/xAxisForceOffsetMin", false).toBool());
221 xAxis()->setAxisInterpret(dialogDefaults().value(defaultsGroupName()+"/xAxisInterpret", false).toBool());
222 xAxis()->setAxisInterpretation((AxisInterpretationType)dialogDefaults().value(defaultsGroupName()+"/xAxisInterpretation", 1).toInt());
223 xAxis()->setAxisDisplay((AxisDisplayType)dialogDefaults().value(defaultsGroupName()+"/xAxisDisplay", 4).toInt());
224 xAxis()->setTimezoneName(dialogDefaults().value(defaultsGroupName()+"/xAxisTimezone", "GMT").toString());
225 xAxis()->setAxisMajorTickMode((MajorTickMode)dialogDefaults().value(defaultsGroupName()+"/xAxisMajorTickMode", 5).toInt());
226 xAxis()->setAxisMinorTickCount(dialogDefaults().value(defaultsGroupName()+"/xAxisMinorTickCount", 5).toInt());
227 xAxis()->setAxisAutoMinorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisautoMinorTickCount", true).toBool());
228 xAxis()->setDrawAxisMajorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorTicks", true).toBool());
229 xAxis()->setDrawAxisMinorTicks(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorTicks", true).toBool());
230 xAxis()->setDrawAxisMajorGridLines(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLines", true).toBool());
231 xAxis()->setDrawAxisMinorGridLines(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLines", false).toBool());
232
233 xAxis()->setAxisMajorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineStyle", 2).toInt());
234 xAxis()->setAxisMajorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineWidth",1).toDouble());
235 color = dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMajorGridLineColor", "#a0a0a4").value<QColor>();
236 xAxis()->setAxisMajorGridLineColor(color);
237
238 xAxis()->setAxisMinorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineStyle", 2).toInt());
239 xAxis()->setAxisMinorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineWidth",1).toDouble());
240 color = dialogDefaults().value(defaultsGroupName()+"/xAxisDrawMinorGridLineColor", "#a0a0a4").value<QColor>();
241 xAxis()->setAxisMinorGridLineColor(color);
242
243 xAxis()->setAxisSignificantDigits(dialogDefaults().value(defaultsGroupName()+"/xAxisSignificantDigits",9).toInt());
244 xAxis()->setAxisLabelRotation(dialogDefaults().value(defaultsGroupName()+"/xAxisRotation",0).toDouble());
245
246
247 yAxis()->setAxisVisible(dialogDefaults().value(defaultsGroupName()+"/yAxisVisible", true).toBool());
248 yAxis()->setAxisLog(dialogDefaults().value(defaultsGroupName()+"/yAxisLog", false).toBool());
249 yAxis()->setAxisReversed(dialogDefaults().value(defaultsGroupName()+"/yAxisReversed", false).toBool());
250 yAxis()->setAxisAutoBaseOffset(dialogDefaults().value(defaultsGroupName()+"/yAxisAutoBaseOffset", true).toBool());
251 yAxis()->setAxisBaseOffset(dialogDefaults().value(defaultsGroupName()+"/yAxisBaseOffset", false).toBool());
252 yAxis()->setAxisForceOffsetMin(dialogDefaults().value(defaultsGroupName()+"/yAxisForceOffsetMin", false).toBool());
253 yAxis()->setAxisInterpret(dialogDefaults().value(defaultsGroupName()+"/yAxisInterpret", false).toBool());
254 yAxis()->setAxisInterpretation((AxisInterpretationType)dialogDefaults().value(defaultsGroupName()+"/yAxisInterpretation", 1).toInt());
255 yAxis()->setAxisDisplay((AxisDisplayType)dialogDefaults().value(defaultsGroupName()+"/yAxisDisplay", 4).toInt());
256 yAxis()->setTimezoneName(dialogDefaults().value(defaultsGroupName()+"/yAxisTimezone", "GMT").toString());
257 yAxis()->setAxisMajorTickMode((MajorTickMode)dialogDefaults().value(defaultsGroupName()+"/yAxisMajorTickMode", 5).toInt());
258 yAxis()->setAxisMinorTickCount(dialogDefaults().value(defaultsGroupName()+"/yAxisMinorTickCount", 5).toInt());
259 yAxis()->setAxisAutoMinorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisautoMinorTickCount", true).toBool());
260 yAxis()->setDrawAxisMajorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorTicks", true).toBool());
261 yAxis()->setDrawAxisMinorTicks(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorTicks", true).toBool());
262 yAxis()->setDrawAxisMajorGridLines(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLines", true).toBool());
263 yAxis()->setDrawAxisMinorGridLines(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLines", false).toBool());
264
265 yAxis()->setAxisMajorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineStyle", 2).toInt());
266 yAxis()->setAxisMajorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineWidth",1).toDouble());
267 color = dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMajorGridLineColor", "#a0a0a4").value<QColor>();
268 yAxis()->setAxisMajorGridLineColor(color);
269
270 yAxis()->setAxisMinorGridLineStyle((Qt::PenStyle)dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineStyle", 2).toInt());
271 yAxis()->setAxisMinorGridLineWidth(dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineWidth",1).toDouble());
272 color = dialogDefaults().value(defaultsGroupName()+"/yAxisDrawMinorGridLineColor", "#a0a0a4").value<QColor>();
273 yAxis()->setAxisMinorGridLineColor(color);
274
275 yAxis()->setAxisSignificantDigits(dialogDefaults().value(defaultsGroupName()+"/yAxisSignificantDigits",9).toInt());
276 yAxis()->setAxisLabelRotation(dialogDefaults().value(defaultsGroupName()+"/yAxisRotation",0).toDouble());
277
278 }
279
280
~PlotItem()281 PlotItem::~PlotItem() {
282 delete _xAxis;
283 delete _yAxis;
284 delete _leftLabelDetails;
285 delete _rightLabelDetails;
286 delete _topLabelDetails;
287 delete _bottomLabelDetails;
288 delete _numberLabelDetails;
289 delete _zoomMenu;
290 delete _filterMenu;
291 delete _fitMenu;
292 delete _editMenu;
293
294 if (_sharedAxisBoxMenu) {
295 delete _sharedAxisBoxMenu;
296 }
297 if (_copyMenu) {
298 delete _copyMenu;
299 }
300
301 }
302
_initializeShortName()303 void PlotItem::_initializeShortName() {
304 _shortName = 'P'+QString::number(_plotnum);
305 if (_plotnum>max_plotnum) {
306 max_plotnum = _plotnum;
307 }
308 _plotnum++;
309 }
310
plotName() const311 QString PlotItem::plotName() const {
312 return Name();
313 }
314
plotCleanedName() const315 QString PlotItem::plotCleanedName() const {
316 return CleanedName();
317 }
318
save(QXmlStreamWriter & xml)319 void PlotItem::save(QXmlStreamWriter &xml) {
320 if (isVisible()) {
321 bool plot_maximized = _plotMaximized;
322 // We don't save 'plot maximized' mode - so un-do it before saving
323 if (plot_maximized) {
324 plotMaximize();
325 }
326 xml.writeStartElement("plot");
327 xml.writeAttribute("tiedxzoom", QVariant(isXTiedZoom()).toString());
328 xml.writeAttribute("tiedyzoom", QVariant(isYTiedZoom()).toString());
329 xml.writeAttribute("leftlabelvisible", QVariant(_leftLabelDetails->isVisible()).toString());
330 xml.writeAttribute("bottomlabelvisible", QVariant(_bottomLabelDetails->isVisible()).toString());
331 xml.writeAttribute("rightlabelvisible", QVariant(_rightLabelDetails->isVisible()).toString());
332 xml.writeAttribute("toplabelvisible", QVariant(_topLabelDetails->isVisible()).toString());
333 xml.writeAttribute("globalfont", QVariant(_globalFont).toString());
334 xml.writeAttribute("globalfontscale", QVariant(_globalFontScale).toString());
335 xml.writeAttribute("globalfontcolor", QVariant(_globalFontColor).toString());
336 xml.writeAttribute("showlegend", QVariant(_showLegend).toString());
337 xml.writeAttribute("hidebottomaxislabel", QVariant(_manuallyHideBottomAxisLabel).toString());
338 xml.writeAttribute("hidetopaxislabel", QVariant(_manuallyHideTopAxisLabel).toString());
339 xml.writeAttribute("hideleftaxislabel", QVariant(_manuallyHideLeftAxisLabel).toString());
340 xml.writeAttribute("hiderightaxislabel", QVariant(_manuallyHideRightAxisLabel).toString());
341 xml.writeAttribute("numberaxislabelscale", QVariant(_useNumberAxisLabelScale).toString());
342 saveNameInfo(xml, PLOTNUM);
343
344 ViewItem::save(xml);
345 legend()->saveInPlot(xml);
346
347 foreach (PlotRenderItem *renderer, renderItems()) {
348 renderer->saveInPlot(xml);
349 }
350 _xAxis->saveInPlot(xml, QString("xaxis"));
351 _yAxis->saveInPlot(xml, QString("yaxis"));
352 _leftLabelDetails->saveInPlot(xml, QString("leftlabel"));
353 _rightLabelDetails->saveInPlot(xml, QString("rightlabel"));
354 _topLabelDetails->saveInPlot(xml, QString("toplabel"));
355 _bottomLabelDetails->saveInPlot(xml, QString("bottomlabel"));
356 _numberLabelDetails->saveInPlot(xml, QString("numberlabel"));
357
358 xml.writeStartElement("projectionrect");
359 xml.writeAttribute("x", QVariant(projectionRect().x()).toString());
360 xml.writeAttribute("y", QVariant(projectionRect().y()).toString());
361 xml.writeAttribute("width", QVariant(projectionRect().width()).toString());
362 xml.writeAttribute("height", QVariant(projectionRect().height()).toString());
363 xml.writeEndElement();
364 xml.writeEndElement();
365 if (plot_maximized) {
366 plotMaximize(); // re-maximize it if we just un-maximized it.
367 }
368 }
369 }
370
371
edit(PlotClickEditRegion region)372 void PlotItem::edit(PlotClickEditRegion region) {
373 PlotItemDialog *editDialog = new PlotItemDialog(this, kstApp->mainWindow());
374 if (region == LABEL) {
375 editDialog->selectLabelsPage();
376 } else if (region == XAXIS) {
377 editDialog->selectXAxisPage();
378 } else if (region == YAXIS) {
379 editDialog->selectYAxisPage();
380 }
381 editDialog->show();
382 }
383
384
createActions()385 void PlotItem::createActions() {
386
387 _createCurve = new QAction(tr("Create Curve"), this);
388 connect(_createCurve, SIGNAL(triggered()), this, SLOT(showCurveDialog()));
389
390 _zoomMaximum = new QAction(tr("Zoom Maximum"), this);
391 _zoomMaximum->setShortcut(Qt::Key_M);
392 registerShortcut(_zoomMaximum);
393 connect(_zoomMaximum, SIGNAL(triggered()), this, SLOT(zoomMaximum()));
394
395 _zoomMaxSpikeInsensitive = new QAction(tr("Zoom Max Spike Insensitive"), this);
396 _zoomMaxSpikeInsensitive->setShortcut(Qt::Key_S);
397 registerShortcut(_zoomMaxSpikeInsensitive);
398 connect(_zoomMaxSpikeInsensitive, SIGNAL(triggered()), this, SLOT(zoomMaxSpikeInsensitive()));
399
400 _zoomPrevious = _undoStack->createUndoAction(this, tr("Zoom Previous"));
401 _zoomPrevious->setShortcut(Qt::Key_R);
402 registerShortcut(_zoomPrevious);
403
404 _zoomTied = new QAction(tr("Zoom Tied"), this);
405 _zoomTied->setShortcut(Qt::Key_T);
406 _zoomTied->setCheckable(true);
407 registerShortcut(_zoomTied);
408 connect(_zoomTied, SIGNAL(triggered()), this, SLOT(zoomTied()));
409
410 _zoomOut = new QAction(tr("Zoom Out"), this);
411 _zoomOut->setShortcut(Qt::Key_Minus);
412 registerShortcut(_zoomOut);
413 connect(_zoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
414
415 _zoomIn = new QAction(tr("Zoom In"), this);
416 _zoomIn->setShortcut(Qt::Key_Plus);
417 registerShortcut(_zoomIn);
418 connect(_zoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
419
420 _zoomXTied = new QAction(tr("Zoom X Tied"), this);
421 _zoomXTied->setShortcut(Qt::CTRL+Qt::Key_T);
422 _zoomXTied->setCheckable(true);
423 registerShortcut(_zoomXTied);
424 connect(_zoomXTied, SIGNAL(triggered()), this, SLOT(zoomXTied()));
425
426 _zoomYTied = new QAction(tr("Zoom Y Tied"), this);
427 _zoomYTied->setShortcut(Qt::SHIFT+Qt::Key_T);
428 _zoomYTied->setCheckable(true);
429 registerShortcut(_zoomYTied);
430 connect(_zoomYTied, SIGNAL(triggered()), this, SLOT(zoomYTied()));
431
432 _zoomMeanCentered = new QAction(tr("Zoom Mean-centered Y"), this);
433 _zoomMeanCentered->setShortcut(Qt::Key_A);
434 registerShortcut(_zoomMeanCentered);
435 connect(_zoomMeanCentered, SIGNAL(triggered()), this, SLOT(zoomMeanCentered()));
436
437 _zoomXMaximum = new QAction(tr("X-Zoom Maximum"), this);
438 _zoomXMaximum->setShortcut(Qt::CTRL+Qt::Key_M);
439 registerShortcut(_zoomXMaximum);
440 connect(_zoomXMaximum, SIGNAL(triggered()), this, SLOT(zoomXMaximum()));
441
442 _zoomXAutoBorder = new QAction(tr("X-Zoom Auto Border"), this);
443 _zoomXAutoBorder->setShortcut(Qt::CTRL+Qt::Key_B);
444 registerShortcut(_zoomXAutoBorder);
445 connect(_zoomXAutoBorder, SIGNAL(triggered()), this, SLOT(zoomXAutoBorder()));
446
447 _zoomXNoSpike = new QAction(tr("X-Zoom Spike Insensitive"), this);
448 //_zoomXNoSpike->setShortcut(Qt::CTRL+Qt::Key_S);
449 registerShortcut(_zoomXNoSpike);
450 connect(_zoomXNoSpike, SIGNAL(triggered()), this, SLOT(zoomXNoSpike()));
451
452 _zoomXRight = new QAction(tr("X-Zoom Right"), this);
453 _zoomXRight->setShortcut(Qt::Key_Right);
454 registerShortcut(_zoomXRight);
455 connect(_zoomXRight, SIGNAL(triggered()), this, SLOT(zoomXRight()));
456
457 _zoomXFarRight = new QAction(tr("X-Zoom Right by one screen"), this);
458 _zoomXFarRight->setShortcut(Qt::CTRL+Qt::Key_Right);
459 registerShortcut(_zoomXFarRight);
460 connect(_zoomXFarRight, SIGNAL(triggered()), this, SLOT(zoomXFarRight()));
461
462 _zoomXLeft= new QAction(tr("X-Zoom Left"), this);
463 _zoomXLeft->setShortcut(Qt::Key_Left);
464 registerShortcut(_zoomXLeft);
465 connect(_zoomXLeft, SIGNAL(triggered()), this, SLOT(zoomXLeft()));
466
467 _zoomXFarLeft= new QAction(tr("X-Zoom Left by one screen"), this);
468 _zoomXFarLeft->setShortcut(Qt::CTRL+Qt::Key_Left);
469 registerShortcut(_zoomXFarLeft);
470 connect(_zoomXFarLeft, SIGNAL(triggered()), this, SLOT(zoomXFarLeft()));
471
472 _zoomXOut = new QAction(tr("X-Zoom Out"), this);
473 _zoomXOut->setShortcut(Qt::SHIFT+Qt::Key_Right);
474 registerShortcut(_zoomXOut);
475 connect(_zoomXOut, SIGNAL(triggered()), this, SLOT(zoomXOut()));
476
477 _zoomXIn = new QAction(tr("X-Zoom In"), this);
478 _zoomXIn->setShortcut(Qt::SHIFT+Qt::Key_Left);
479 registerShortcut(_zoomXIn);
480 connect(_zoomXIn, SIGNAL(triggered()), this, SLOT(zoomXIn()));
481
482 _zoomNormalizeXtoY = new QAction(tr("Normalize X-axis to Y-axis"), this);
483 _zoomNormalizeXtoY->setShortcut(Qt::Key_N);
484 registerShortcut(_zoomNormalizeXtoY);
485 connect(_zoomNormalizeXtoY, SIGNAL(triggered()), this, SLOT(zoomNormalizeXtoY()));
486
487 _zoomLogX = new QAction(tr("Log X-axis"), this);
488 _zoomLogX->setShortcut(Qt::Key_G);
489 _zoomLogX->setCheckable(true);
490 registerShortcut(_zoomLogX);
491 connect(_zoomLogX, SIGNAL(triggered()), this, SLOT(zoomLogX()));
492
493 _zoomYLocalMaximum = new QAction(tr("Y-Zoom Local Maximum"), this);
494 _zoomYLocalMaximum->setShortcut(Qt::SHIFT+Qt::Key_L);
495 registerShortcut(_zoomYLocalMaximum);
496 connect(_zoomYLocalMaximum, SIGNAL(triggered()), this, SLOT(zoomYLocalMaximum()));
497
498 _zoomYMaximum = new QAction(tr("Y-Zoom Maximum"), this);
499 _zoomYMaximum->setShortcut(Qt::SHIFT+Qt::Key_M);
500 registerShortcut(_zoomYMaximum);
501 connect(_zoomYMaximum, SIGNAL(triggered()), this, SLOT(zoomYMaximum()));
502
503 _zoomYAutoBorder = new QAction(tr("Y-Zoom Auto Border"), this);
504 _zoomYAutoBorder->setShortcut(Qt::SHIFT+Qt::Key_B);
505 registerShortcut(_zoomYAutoBorder);
506 connect(_zoomYAutoBorder, SIGNAL(triggered()), this, SLOT(zoomYAutoBorder()));
507
508 _zoomYNoSpike = new QAction(tr("Y-Zoom Spike Insensitive"), this);
509 _zoomYNoSpike->setShortcut(Qt::SHIFT+Qt::Key_S);
510 registerShortcut(_zoomYNoSpike);
511 connect(_zoomYNoSpike, SIGNAL(triggered()), this, SLOT(zoomYNoSpike()));
512
513 _zoomYUp= new QAction(tr("Y-Zoom Up"), this);
514 _zoomYUp->setShortcut(Qt::Key_Up);
515 registerShortcut(_zoomYUp);
516 connect(_zoomYUp, SIGNAL(triggered()), this, SLOT(zoomYUp()));
517
518 _zoomYDown= new QAction(tr("Y-Zoom Down"), this);
519 _zoomYDown->setShortcut(Qt::Key_Down);
520 registerShortcut(_zoomYDown);
521 connect(_zoomYDown, SIGNAL(triggered()), this, SLOT(zoomYDown()));
522
523 _zoomYOut = new QAction(tr("Y-Zoom Out"), this);
524 _zoomYOut->setShortcut(Qt::SHIFT+Qt::Key_Up);
525 registerShortcut(_zoomYOut);
526 connect(_zoomYOut, SIGNAL(triggered()), this, SLOT(zoomYOut()));
527
528 _zoomYIn = new QAction(tr("Y-Zoom In"), this);
529 _zoomYIn->setShortcut(Qt::SHIFT+Qt::Key_Down);
530 registerShortcut(_zoomYIn);
531 connect(_zoomYIn, SIGNAL(triggered()), this, SLOT(zoomYIn()));
532
533 _zoomNormalizeYtoX = new QAction(tr("Normalize Y-axis to X-axis"), this);
534 _zoomNormalizeYtoX->setShortcut(Qt::SHIFT+Qt::Key_N);
535 registerShortcut(_zoomNormalizeYtoX);
536 connect(_zoomNormalizeYtoX, SIGNAL(triggered()), this, SLOT(zoomNormalizeYtoX()));
537
538 _zoomLogY = new QAction(tr("Log Y Axis"), this);
539 _zoomLogY->setShortcut(Qt::Key_L);
540 _zoomLogY->setCheckable(true);
541 registerShortcut(_zoomLogY);
542 connect(_zoomLogY, SIGNAL(triggered()), this, SLOT(zoomLogY()));
543
544 _adjustImageColorscale = new QAction(tr("Adjust Image Color Scale"), this);
545 _adjustImageColorscale->setShortcut(Qt::Key_I);
546 registerShortcut(_adjustImageColorscale);
547 connect(_adjustImageColorscale, SIGNAL(triggered()), this, SLOT(adjustImageColorScale()));
548
549 createZoomMenu();
550
551 _plotMaximize = new QAction(tr("Maximize Plot"), this);
552 _plotMaximize->setShortcut(Qt::Key_Z);
553 _plotMaximize->setCheckable(true);
554 registerShortcut(_plotMaximize);
555 connect(_plotMaximize, SIGNAL(triggered()), this, SLOT(plotMaximize()));
556
557
558 _shareBoxShareX = new QAction(tr("Share Plots on X-Axis"), this);
559 _shareBoxShareX->setCheckable(true);
560 registerShortcut(_shareBoxShareX);
561 connect(_shareBoxShareX, SIGNAL(triggered()), this, SIGNAL(shareXAxisTriggered()));
562
563 _shareBoxShareY = new QAction(tr("Share Plots on Y-Axis"), this);
564 _shareBoxShareY->setCheckable(true);
565 registerShortcut(_shareBoxShareY);
566 connect(_shareBoxShareY, SIGNAL(triggered()), this, SIGNAL(shareYAxisTriggered()));
567
568 _breakSharedBox = new QAction(tr("Break Shared Axis Box"), this);
569 registerShortcut(_breakSharedBox);
570 connect(_breakSharedBox, SIGNAL(triggered()), this, SIGNAL(breakShareTriggered()));
571
572 _copyStatus = new QAction(tr("Copy Coordinates"), this);
573 _copyStatus->setShortcut(Qt::CTRL + Qt::Key_C);
574 registerShortcut(_copyStatus);
575 connect(_copyStatus, SIGNAL(triggered()), this, SLOT(copyStatus()));
576
577 _copyXCoord = new QAction(tr("Copy X Coordinate"), this);
578 _copyXCoord->setShortcut(Qt::Key_X);
579 registerShortcut(_copyXCoord);
580 connect(_copyXCoord, SIGNAL(triggered()), this, SLOT(copyXCoord()));
581
582 _copyYCoord = new QAction(tr("Copy Y Coordinate"), this);
583 _copyYCoord->setShortcut(Qt::Key_Y);
584 registerShortcut(_copyYCoord);
585 connect(_copyYCoord, SIGNAL(triggered()), this, SLOT(copyYCoord()));
586
587 createCopyMenu();
588
589 referenceMode = new QAction(tr("Place Reference Marker"), this);
590 referenceMode->setShortcut(Qt::Key_C);
591 registerShortcut(referenceMode);
592
593 referenceModeDisabled = new QAction(tr("Remove Reference Marker"), this);
594 referenceModeDisabled->setShortcut(Qt::SHIFT + Qt::Key_C);
595 registerShortcut(referenceModeDisabled);
596
597 }
598
createCopyMenu()599 void PlotItem::createCopyMenu() {
600 if (_copyMenu) {
601 delete _copyMenu;
602 }
603
604 _copyMenu = new QMenu;
605 _copyMenu->setTitle(tr("Copy"));
606
607 _copyMenu->addAction(_copyStatus);
608 _copyMenu->addAction(_copyXCoord);
609 _copyMenu->addAction(_copyYCoord);
610
611 }
612
createZoomMenu()613 void PlotItem::createZoomMenu() {
614 if (_zoomMenu) {
615 delete _zoomMenu;
616 }
617
618 _zoomMenu = new QMenu;
619 _zoomMenu->setTitle(tr("Zoom"));
620
621 QMenu *xyZoomMenu = _zoomMenu->addMenu(tr("XY Zoom", "menu title: zoom in both axis of a plot"));
622 QMenu *yZoomMenu = _zoomMenu->addMenu(tr("Y Zoom", "menu title: zoom in the horizontal axis of a plot"));
623 QMenu *xZoomMenu = _zoomMenu->addMenu(tr("X Zoom", "menu title: zoom in the vertical axis of a plot"));
624
625 _zoomMenu->addAction(_zoomPrevious);
626 _zoomMenu->addAction(_adjustImageColorscale);
627
628 xyZoomMenu->addAction(_zoomMaximum);
629 xyZoomMenu->addAction(_zoomMaxSpikeInsensitive);
630 xyZoomMenu->addAction(_zoomMeanCentered);
631 xyZoomMenu->addAction(_zoomTied);
632
633 xZoomMenu->addAction(_zoomXTied);
634 xZoomMenu->addAction(_zoomXMaximum);
635 xZoomMenu->addAction(_zoomXAutoBorder);
636 xZoomMenu->addAction(_zoomXNoSpike);
637 xZoomMenu->addAction(_zoomXRight);
638 xZoomMenu->addAction(_zoomXLeft);
639 xZoomMenu->addAction(_zoomXFarRight);
640 xZoomMenu->addAction(_zoomXFarLeft);
641 xZoomMenu->addAction(_zoomXOut);
642 xZoomMenu->addAction(_zoomXIn);
643 xZoomMenu->addAction(_zoomNormalizeXtoY);
644 xZoomMenu->addAction(_zoomLogX);
645
646
647 yZoomMenu->addAction(_zoomYTied);
648 yZoomMenu->addAction(_zoomYLocalMaximum);
649 yZoomMenu->addAction(_zoomYMaximum);
650 yZoomMenu->addAction(_zoomYAutoBorder);
651 yZoomMenu->addAction(_zoomYNoSpike);
652 yZoomMenu->addAction(_zoomYUp);
653 yZoomMenu->addAction(_zoomYDown);
654 yZoomMenu->addAction(_zoomYOut);
655 yZoomMenu->addAction(_zoomYIn);
656 yZoomMenu->addAction(_zoomNormalizeYtoX);
657 yZoomMenu->addAction(_zoomLogY);
658 }
659
660
curveList() const661 CurveList PlotItem::curveList() const {
662 CurveList list;
663 foreach (PlotRenderItem *renderer, renderItems()) {
664 foreach (RelationPtr relation, renderer->relationList()) {
665 if (CurvePtr curve = kst_cast<Curve>(relation)) {
666 list << curve;
667 }
668 }
669 }
670 return list;
671 }
672
673
relationList() const674 RelationList PlotItem::relationList() const {
675 RelationList list;
676 foreach (PlotRenderItem *renderer, renderItems()) {
677 foreach (RelationPtr relation, renderer->relationList()) {
678 list << relation;
679 }
680 }
681
682 return list;
683 }
684
685
createFilterMenu()686 void PlotItem::createFilterMenu() {
687 if (_filterMenu) {
688 delete _filterMenu;
689 }
690
691 _filterMenu = new QMenu;
692 _filterMenu->setTitle(tr("Create Filter"));
693
694 CurveList curves = curveList();
695 foreach (const CurvePtr& curve, curves) {
696 _filterMenu->addAction(new QAction(curve->Name(), this));
697 }
698 connect(_filterMenu, SIGNAL(triggered(QAction*)), this, SLOT(showFilterDialog(QAction*)));
699 }
700
701
createEditMenu()702 void PlotItem::createEditMenu() {
703 if (_editMenu) {
704 delete _editMenu;
705 }
706
707 _editMenu = new QMenu;
708
709 int nc = curveList().size();
710 int nr = relationList().size();
711 if (nc == nr) {
712 _editMenu->setTitle(tr("Edit Curve"));
713 } else if (nc == 0) {
714 _editMenu->setTitle(tr("Edit Image"));
715 } else {
716 _editMenu->setTitle(tr("Edit Curve/Image"));
717 }
718
719 RelationList relations = relationList();
720 foreach (const RelationPtr& relation, relations) {
721 _editMenu->addAction(new QAction(relation->Name(), this));
722 }
723 connect(_editMenu, SIGNAL(triggered(QAction*)), this, SLOT(showEditDialog(QAction*)));
724 }
725
726
createFitMenu()727 void PlotItem::createFitMenu() {
728 if (_fitMenu) {
729 delete _fitMenu;
730 }
731
732 _fitMenu = new QMenu;
733 _fitMenu->setTitle(tr("Create Fit"));
734
735 CurveList curves = curveList();
736 foreach (const CurvePtr& curve, curves) {
737 _fitMenu->addAction(new QAction(curve->Name(), this));
738 }
739
740 connect(_fitMenu, SIGNAL(triggered(QAction*)), this, SLOT(showFitDialog(QAction*)));
741 }
742
createPSDMenu()743 void PlotItem::createPSDMenu() {
744 if (_psdMenu) {
745 delete _psdMenu;
746 }
747
748 _psdMenu = new QMenu;
749 _psdMenu->setTitle(tr("Create Spectrum"));
750
751 CurveList curves = curveList();
752 foreach (const CurvePtr& curve, curves) {
753 _psdMenu->addAction(new QAction(curve->Name(), this));
754 }
755
756 connect(_psdMenu, SIGNAL(triggered(QAction*)), this, SLOT(showPSDDialog(QAction*)));
757 }
758
759
createHistogramMenu()760 void PlotItem::createHistogramMenu() {
761 if (_histogramMenu) {
762 delete _histogramMenu;
763 }
764
765 _histogramMenu = new QMenu;
766 _histogramMenu->setTitle(tr("Create Histogram"));
767
768 CurveList curves = curveList();
769 foreach (const CurvePtr& curve, curves) {
770 _histogramMenu->addAction(new QAction(curve->Name(), this));
771 }
772
773 connect(_histogramMenu, SIGNAL(triggered(QAction*)), this, SLOT(showHistogramDialog(QAction*)));
774 }
775
776
777
createSharedAxisBoxMenu()778 void PlotItem::createSharedAxisBoxMenu() {
779 if (_sharedAxisBoxMenu) {
780 delete _sharedAxisBoxMenu;
781 }
782 _sharedAxisBoxMenu = new QMenu;
783 _sharedAxisBoxMenu->setTitle(tr("Shared Axis Box Settings"));
784
785 _sharedAxisBoxMenu->addAction(_shareBoxShareX);
786 _sharedAxisBoxMenu->addAction(_shareBoxShareY);
787 }
788
789
790
791
addToMenuForContextEvent(QMenu & menu)792 void PlotItem::addToMenuForContextEvent(QMenu &menu) {
793
794 menu.addSeparator();
795 menu.addAction(_createCurve);
796
797 if (curveList().size()>0) {
798 if (!DataObject::filterPluginList().empty()) {
799 createFilterMenu();
800 menu.addMenu(_filterMenu);
801 }
802
803 if (!DataObject::fitsPluginList().empty()) {
804 createFitMenu();
805 menu.addMenu(_fitMenu);
806 }
807 createPSDMenu();
808 menu.addMenu(_psdMenu);
809
810 createHistogramMenu();
811 menu.addMenu(_histogramMenu);
812
813 createEditMenu();
814 menu.addMenu(_editMenu);
815
816 } else if (relationList().size()>0) {
817 menu.addSeparator();
818 createEditMenu();
819 menu.addMenu(_editMenu);
820 }
821
822 if (parentItem() && isInSharedAxisBox() && _sharedBox) {
823 if (view()->viewMode() == View::Data) {
824
825 menu.addSeparator();
826 menu.addMenu(_sharedAxisBoxMenu);
827
828 menu.addAction(_breakSharedBox);
829
830 _shareBoxShareX->setChecked(_sharedBox->isXAxisShared());
831 _shareBoxShareY->setChecked(_sharedBox->isYAxisShared());
832 }
833 }
834
835 if (view()->viewMode() == View::Data) {
836 _plotMaximize->setChecked(_plotMaximized);
837 menu.addSeparator();
838 menu.addAction(_plotMaximize);
839 menu.addAction(referenceMode);
840 menu.addAction(referenceModeDisabled);
841 }
842
843 _zoomLogX->setChecked(xAxis()->axisLog());
844 _zoomLogY->setChecked(yAxis()->axisLog());
845
846 _zoomTied->setChecked(isTiedZoom());
847 _zoomXTied->setChecked(isXTiedZoom());
848 _zoomYTied->setChecked(isYTiedZoom());
849
850 _zoomPrevious->setVisible(!isInSharedAxisBox());
851 menu.addMenu(_zoomMenu);
852
853 menu.addMenu(_copyMenu);
854
855 }
856
857
showEditDialog(QAction * action)858 void PlotItem::showEditDialog(QAction *action) {
859 RelationList relations = relationList();
860 int n = relations.size();
861 for (int i = 0; i<n; i++) {
862 RelationPtr relation = relations.at(i);
863 if (relation->Name() == action->text()) {
864 DialogLauncher::self()->showObjectDialog(relation);
865 }
866 }
867 }
868
869
showFitFilterDialog(QAction * action,const QString & plugin)870 void PlotItem::showFitFilterDialog(QAction* action, const QString& plugin) {
871 CurveList curves = curveList();
872 foreach (const CurvePtr& curve, curves) {
873 if (curve->Name() == action->text()) {
874 DialogLauncher::self()->showBasicPluginDialog(plugin, 0, curve->xVector(), curve->yVector(), this);
875 }
876 }
877 }
878
showPSDDialog(QAction * action)879 void PlotItem::showPSDDialog(QAction* action) {
880 CurveList curves = curveList();
881 foreach (const CurvePtr& curve, curves) {
882 if (curve->Name() == action->text()) {
883 DialogLauncher::self()->showPowerSpectrumDialog(0, curve->yVector());
884 }
885 }
886 }
887
showCurveDialog()888 void PlotItem::showCurveDialog() {
889 DialogLauncher::self()->showCurveDialog(0,0,this);
890 }
891
892
showHistogramDialog(QAction * action)893 void PlotItem::showHistogramDialog(QAction* action) {
894 CurveList curves = curveList();
895 foreach (const CurvePtr& curve, curves) {
896 if (curve->Name() == action->text()) {
897 DialogLauncher::self()->showHistogramDialog(0, curve->yVector());
898 }
899 }
900 }
901
902
showFilterDialog(QAction * action)903 void PlotItem::showFilterDialog(QAction* action) {
904 showFitFilterDialog(action, DataObject::filterPluginList().first());
905 }
906
showFitDialog(QAction * action)907 void PlotItem::showFitDialog(QAction* action) {
908 showFitFilterDialog(action, DataObject::fitsPluginList().first());
909 }
910
redrawPlot()911 void PlotItem::redrawPlot() {
912 update();
913 }
914
915
handleChangedInputs(qint64 serial)916 bool PlotItem::handleChangedInputs(qint64 serial) {
917 if (!_allowUpdates) {
918 return false;
919 }
920
921 // decide if the inputs have changed
922 bool no_change = true;
923
924 if (_serialOfLastChange==Forced) {
925 no_change = false;
926 } else {
927 foreach (PlotRenderItem *renderer, renderItems()) {
928 foreach (RelationPtr relation, renderer->relationList()) {
929 if (relation->serialOfLastChange() > _serialOfLastChange) {
930 no_change = false;
931 }
932 }
933 }
934 }
935
936 if (no_change) {
937 return false;
938 }
939
940 _serialOfLastChange = serial;
941
942 if (isInSharedAxisBox()) {
943 // Need to update the box's projectionRect.
944 sharedAxisBox()->updateZoomForDataUpdate(serial);
945 }
946
947 QRectF compute = computedProjectionRect();
948 QRectF newProjectionRec = projectionRect();
949
950 if ((xAxis()->axisZoomMode() == PlotAxis::Auto) ||
951 (xAxis()->axisZoomMode() == PlotAxis::MeanCentered) ||
952 (xAxis()->axisZoomMode() == PlotAxis::AutoBorder) ||
953 (xAxis()->axisZoomMode() == PlotAxis::SpikeInsensitive)) {
954
955 newProjectionRec.setWidth(0.1);
956 newProjectionRec.setLeft(0.0);
957 newProjectionRec.setLeft(compute.x());
958 newProjectionRec.setWidth(compute.width());
959 }
960
961 if ((yAxis()->axisZoomMode() == PlotAxis::AutoBorder) ||
962 (yAxis()->axisZoomMode() == PlotAxis::Auto) ||
963 (yAxis()->axisZoomMode() == PlotAxis::SpikeInsensitive) ||
964 (yAxis()->axisZoomMode() == PlotAxis::MeanCentered)) {
965 newProjectionRec.setHeight(0.1);
966 newProjectionRec.setTop(0.0);
967 newProjectionRec.setTop(compute.y());
968 newProjectionRec.setHeight(compute.height());
969 }
970
971 setProjectionRect(newProjectionRec);
972
973 setLabelsDirty();
974
975 return true;
976 }
977
978
renderItems() const979 QList<PlotRenderItem*> PlotItem::renderItems() const {
980 return _renderers.values();
981 }
982
983
renderItem(PlotRenderItem::RenderType type)984 PlotRenderItem *PlotItem::renderItem(PlotRenderItem::RenderType type) {
985 if ((type == PlotRenderItem::First) && (_renderers.count()>0)) {
986 return _renderers.values().at(0);
987 }
988 if (_renderers.contains(type))
989 return _renderers.value(type);
990
991 switch (type) {
992 case PlotRenderItem::Cartesian:
993 {
994 CartesianRenderItem *renderItem = new CartesianRenderItem(this);
995 _renderers.insert(type, renderItem);
996 return renderItem;
997 }
998 case PlotRenderItem::Polar:
999 case PlotRenderItem::Sinusoidal:
1000 default:
1001 return 0;
1002 }
1003 }
1004
1005
calculateBorders(QPainter * painter)1006 void PlotItem::calculateBorders(QPainter *painter) {
1007
1008 calculateLeftLabelMargin(painter);
1009 calculateRightLabelMargin(painter);
1010 calculateTopLabelMargin(painter);
1011 calculateBottomLabelMargin(painter);
1012
1013 calculateBottomTickLabelBound(painter);
1014 calculateLeftTickLabelBound(painter);
1015
1016 calculateMargins();
1017
1018 setPlotRectsDirty();
1019 }
1020
1021
updatePlotPixmap()1022 void PlotItem::updatePlotPixmap() {
1023 #if BENCHMARK
1024 QTime bench_time;
1025 bench_time.start();
1026 #endif
1027
1028 _plotPixmapDirty = false;
1029 if (maskedByMaximization()) {
1030 return;
1031 }
1032
1033 #ifdef QT5
1034 int device_pixel_ratio = view()->devicePixelRatio();
1035 #else
1036 int device_pixel_ratio = 1;
1037 #endif
1038
1039 QPixmap pixmap(device_pixel_ratio*(rect().width()+1), device_pixel_ratio*(rect().height()+1));
1040 #ifdef QT5
1041 pixmap.setDevicePixelRatio(device_pixel_ratio);
1042 #endif
1043
1044 pixmap.fill(Qt::transparent);
1045 QPainter pixmapPainter(&pixmap);
1046
1047 //pixmapPainter.setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1048
1049 pixmapPainter.save();
1050 if (rect().topLeft() != QPointF(0, 0)) {
1051 pixmapPainter.translate(-rect().topLeft());
1052 }
1053 paintPixmap(&pixmapPainter);
1054 pixmapPainter.restore();
1055
1056 _plotPixmap = pixmap;
1057 #if BENCHMARK
1058 int i = bench_time.elapsed();
1059 qDebug() << "Total Time to update plot pixmap " << (void *)this << ": " << i << "ms";
1060 #endif
1061 }
1062
1063
paint(QPainter * painter)1064 void PlotItem::paint(QPainter *painter) {
1065 if (maskedByMaximization()) {
1066 return;
1067 }
1068
1069 #if BENCHMARK
1070 QTime bench_time;
1071 bench_time.start();
1072 #endif
1073 if (view()->isPrinting()) {
1074 paintPixmap(painter);
1075 } else {
1076 if (_plotPixmapDirty && rect().isValid()) {
1077 updatePlotPixmap();
1078 }
1079 painter->save();
1080 painter->setPen(Qt::NoPen);
1081 painter->drawRect(rect());
1082 painter->restore();
1083 painter->drawPixmap(rect().topLeft(), _plotPixmap);
1084 if (view()->viewMode() == View::Layout) {
1085 painter->save();
1086 painter->setPen(pen());
1087 painter->setBrush(Qt::NoBrush);
1088 painter->drawRect(rect());
1089 painter->restore();
1090 }
1091 }
1092 #if BENCHMARK
1093 int i = bench_time.elapsed();
1094 qDebug() << "Total Time to paint " << (void *)this << ": " << i << "ms" << endl;
1095 #endif
1096 }
1097
1098
paintPixmap(QPainter * painter)1099 void PlotItem::paintPixmap(QPainter *painter) {
1100 if ((view()->plotBordersDirty() || (creationState() == ViewItem::InProgress)) && rect().isValid()) {
1101 ViewGridLayout::standardizePlotMargins(this, painter);
1102 setPlotBordersDirty(false);
1103 }
1104
1105 painter->save();
1106 painter->setPen(Qt::NoPen);
1107 painter->drawRect(rect());
1108 painter->restore();
1109
1110 painter->save();
1111 bool xTicksUpdated = xAxis()->ticksUpdated();
1112 bool yTicksUpdated = yAxis()->ticksUpdated();
1113 if (xTicksUpdated ||yTicksUpdated) {
1114 resetScaleAxisLabels();
1115 }
1116
1117 painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
1118
1119 paintLeftLabel(painter);
1120 paintBottomLabel(painter);
1121 paintRightLabel(painter);
1122
1123 paintPlot(painter, xTicksUpdated, yTicksUpdated);
1124
1125 paintTickLabels(painter);
1126
1127 paintPlotMarkers(painter);
1128
1129 paintTopLabel(painter);
1130
1131 painter->restore();
1132 }
1133
1134
paintPlot(QPainter * painter,bool xUpdated,bool yUpdated)1135 void PlotItem::paintPlot(QPainter *painter, bool xUpdated, bool yUpdated) {
1136 if (xUpdated) {
1137 xAxis()->validateDrawingRegion(painter);
1138 updateXAxisLines();
1139 updateXAxisLabels(painter);
1140 }
1141 if (yUpdated) {
1142 yAxis()->validateDrawingRegion(painter);
1143 updateYAxisLines();
1144 updateYAxisLabels(painter);
1145 }
1146 if (isUseAxisScale()) {
1147 QFont font(painter->font());
1148 qreal pointSize = qMax((font.pointSizeF() * _numberAxisLabelScaleFactor), ApplicationSettings::self()->minimumFontSize());
1149
1150 font.setPointSizeF(pointSize);
1151 painter->setFont(font);
1152 }
1153
1154 if (_axisLabelsDirty) {
1155 if (!xUpdated) {
1156 updateXAxisLabels(painter);
1157 }
1158 if (!yUpdated) {
1159 updateYAxisLabels(painter);
1160 }
1161 }
1162 #if BENCHMARK > 1
1163 QTime bench_time, benchtmp;
1164 int b_1 = 0, b_2 = 0, b_3 = 0, b_4 = 0, b_5 = 0;
1165 bench_time.start();
1166 benchtmp.start();
1167 #endif
1168 paintMajorGridLines(painter);
1169 #if BENCHMARK > 1
1170 b_1 = benchtmp.elapsed();
1171 #endif
1172 paintMinorGridLines(painter);
1173 #if BENCHMARK > 1
1174 b_2 = benchtmp.elapsed();
1175 #endif
1176 painter->save();
1177 painter->setBrush(Qt::NoBrush);
1178 painter->setPen(pen());
1179 QRectF box(plotRect());
1180 box.adjust(-1.0, -1.0, 0.0, 0.0);
1181 painter->drawRect(box);
1182 #if BENCHMARK > 1
1183 b_3 = benchtmp.elapsed();
1184 #endif
1185
1186 paintMajorTicks(painter);
1187 #if BENCHMARK > 1
1188 b_4 = benchtmp.elapsed();
1189 #endif
1190 paintMinorTicks(painter);
1191 #if BENCHMARK > 1
1192 b_5 = benchtmp.elapsed();
1193 #endif
1194 painter->restore();
1195
1196 #if BENCHMARK > 1
1197 int i = bench_time.elapsed();
1198 qDebug() << "Painting Plot - PaintPlot " << (void *)this << ": " << i << "ms";
1199 if (b_1 > 0) qDebug() << " Major Lines: " << b_1 << "ms";
1200 if (b_2 - b_1 > 0) qDebug() << " Minor Lines: " << (b_2 - b_1) << "ms";
1201 if (b_3 - b_2 > 0) qDebug() << " Rect: " << (b_3 - b_2) << "ms";
1202 if (b_4 - b_3 > 0) qDebug() << " Major Ticks: " << (b_4 - b_3) << "ms";
1203 if (b_5 - b_4 > 0) qDebug() << " Minor Ticks: " << (b_5 - b_4) << "ms";
1204 #endif
1205 }
1206
1207
updateXAxisLines()1208 void PlotItem::updateXAxisLines() {
1209 qreal majorTickLength = qMin(rect().width(), rect().height()) * .02; //two percent
1210 qreal minorTickLength = qMin(rect().width(), rect().height()) * 0.01; //one percent
1211 QRectF rect = plotRect();
1212
1213 _xMajorGridLines.clear();
1214 _xMajorTickLines.clear();
1215 foreach (qreal x, _xAxis->axisMajorTicks()) {
1216 QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1217 QPointF p2 = p1 - QPointF(0, rect.height());
1218 _xMajorGridLines << QLineF(p1, p2);
1219
1220 p2 = p1 - QPointF(0, majorTickLength);
1221 _xMajorTickLines << QLineF(p1, p2);
1222
1223 p1.setY(rect.top());
1224 p2 = p1 + QPointF(0, majorTickLength);
1225 _xMajorTickLines << QLineF(p1, p2);
1226 }
1227 _xMinorGridLines.clear();
1228 _xMinorTickLines.clear();
1229 foreach (qreal x, _xAxis->axisMinorTicks()) {
1230 QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1231 QPointF p2 = p1 - QPointF(0, rect.height());
1232 _xMinorGridLines << QLineF(p1, p2);
1233
1234 p2 = p1 - QPointF(0, minorTickLength);
1235 _xMinorTickLines << QLineF(p1, p2);
1236
1237 p1.setY(rect.top());
1238 p2 = p1 + QPointF(0, minorTickLength);
1239 _xMinorTickLines << QLineF(p1, p2);
1240 }
1241 _xPlotMarkerLines.clear();
1242 foreach (double x, _xAxis->axisPlotMarkers().markers()) {
1243 double xx = _xAxis->axisLog() ? logXLo(x) : x;
1244 if (xx > _xMin && xx < _xMax) {
1245 QPointF p1 = QPointF(mapXToPlot(x), rect.bottom());
1246 QPointF p2 = p1 - QPointF(0, rect.height());
1247 _xPlotMarkerLines << QLineF(p1, p2);
1248 }
1249 }
1250 }
1251
1252
updateXAxisLabels(QPainter * painter)1253 void PlotItem::updateXAxisLabels(QPainter* painter) {
1254 int flags = Qt::TextSingleLine | Qt::AlignCenter;
1255 _xPlotLabels.clear();
1256
1257 int rotation = _xAxis->axisLabelRotation();
1258 painter->save();
1259 QTransform t;
1260 t.rotate(rotation);
1261
1262 QMapIterator<double, QString> xLabelIt(_xAxis->axisLabels());
1263 while (xLabelIt.hasNext()) {
1264 xLabelIt.next();
1265
1266 QRectF bound = painter->boundingRect(QRectF(), flags, xLabelIt.value());
1267 QPointF p;
1268 if (rotation == 0) {
1269 p = QPointF(mapXToPlot(xLabelIt.key()), plotRect().bottom() + bound.height()*0.5 + _calculatedAxisMarginVLead);
1270 bound.moveCenter(p);
1271 } else {
1272 if (rotation < 0) {
1273 qreal theta = (rotation >-30 ? rotation : -30);
1274 qreal right = mapXToPlot(xLabelIt.key()) - bound.height() * (sin(theta*M_PI/180.0));
1275 bound = t.mapRect(bound);
1276 p = QPointF(right, plotRect().bottom() + _calculatedAxisMarginVLead);
1277 bound.moveTopRight(p);
1278 } else {
1279 qreal theta = (rotation <30 ? rotation : 30);
1280 qreal left = mapXToPlot(xLabelIt.key()) - bound.height() * (sin(theta*M_PI/180.0));
1281 bound = t.mapRect(bound);
1282 p = QPointF(left, plotRect().bottom() + _calculatedAxisMarginVLead);
1283 bound.moveTopLeft(p);
1284 }
1285 }
1286
1287 if (rect().left() > bound.left()) {
1288 bound.setLeft(rect().left());
1289 }
1290
1291 if (rect().right() >= bound.right()) { // if no overflow to the right...
1292 CachedPlotLabel label;
1293 label.bound = bound;
1294 label.value = xLabelIt.value();
1295 _xPlotLabels.append(label);
1296 }
1297 }
1298 painter->restore();
1299
1300 if (!_xAxis->baseLabel().isEmpty()) {
1301 QRectF bound = painter->boundingRect(QRectF(), flags, _xAxis->baseLabel());
1302 QPointF p = QPointF(plotRect().left(), plotRect().bottom() + bound.height() * 2.0 + _calculatedAxisMarginVLead);
1303 bound.moveBottomLeft(p);
1304
1305 CachedPlotLabel label;
1306 label.bound = bound;
1307 label.value = _xAxis->baseLabel();
1308 label.baseLabel = true;
1309 _xPlotLabels.append(label);
1310 }
1311 }
1312
1313
setPlotRectsDirty()1314 void PlotItem::setPlotRectsDirty() {
1315 _plotRectsDirty = true;
1316 xAxis()->setTicksUpdated();
1317 yAxis()->setTicksUpdated();
1318 setPlotPixmapDirty();
1319 }
1320
1321
updateYAxisLines()1322 void PlotItem::updateYAxisLines() {
1323 qreal majorTickLength = qMin(rect().width(), rect().height()) * .02; //two percent
1324 qreal minorTickLength = qMin(rect().width(), rect().height()) * 0.01; //one percent
1325 QRectF rect = plotRect();
1326
1327 _yMajorGridLines.clear();
1328 _yMajorTickLines.clear();
1329 foreach (qreal y, _yAxis->axisMajorTicks()) {
1330 QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1331 QPointF p2 = p1 + QPointF(rect.width(), 0);
1332 _yMajorGridLines << QLineF(p1, p2);
1333
1334 p2 = p1 + QPointF(majorTickLength, 0);
1335 _yMajorTickLines << QLineF(p1, p2);
1336
1337 p1.setX(rect.right());
1338 p2 = p1 - QPointF(majorTickLength, 0);
1339 _yMajorTickLines << QLineF(p1, p2);
1340 }
1341
1342 _yMinorGridLines.clear();
1343 _yMinorTickLines.clear();
1344 foreach (qreal y, _yAxis->axisMinorTicks()) {
1345 QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1346 QPointF p2 = p1 + QPointF(rect.width(), 0);
1347 _yMinorGridLines << QLineF(p1, p2);
1348
1349 p2 = p1 + QPointF(minorTickLength, 0);
1350 _yMinorTickLines << QLineF(p1, p2);
1351
1352 p1.setX(rect.right());
1353 p2 = p1 - QPointF(minorTickLength, 0);
1354 _yMinorTickLines << QLineF(p1, p2);
1355 }
1356 _yPlotMarkerLines.clear();
1357 foreach (double y, _yAxis->axisPlotMarkers().markers()) {
1358 double yy = _yAxis->axisLog() ? logYLo(y) : y;
1359 if (yy > _yMin && yy < _yMax) {
1360 QPointF p1 = QPointF(rect.left(), mapYToPlot(y));
1361 QPointF p2 = p1 + QPointF(rect.width(), 0);
1362 _yPlotMarkerLines << QLineF(p1, p2);
1363 }
1364 }
1365 }
1366
1367
updateYAxisLabels(QPainter * painter)1368 void PlotItem::updateYAxisLabels(QPainter* painter) {
1369 int flags = Qt::TextSingleLine | Qt::AlignCenter;
1370 _yPlotLabels.clear();
1371
1372 int rotation = _yAxis->axisLabelRotation();
1373
1374 QTransform t;
1375 t.rotate(rotation);
1376
1377 QMapIterator<double, QString> yLabelIt(_yAxis->axisLabels());
1378 while (yLabelIt.hasNext()) {
1379 yLabelIt.next();
1380
1381 QRectF bound = painter->boundingRect(QRectF(), flags, yLabelIt.value());
1382 QPointF p;
1383 if (rotation < 0) {
1384 qreal theta = (rotation >-45.0) ? rotation : -45.0;
1385 qreal top;
1386 if (rotation >-89) {
1387 top = mapYToPlot(yLabelIt.key()) - bound.height()*0.5*cos(theta*2.0*M_PI/180.0);
1388 } else {
1389 top = mapYToPlot(yLabelIt.key()) - bound.width()*0.5;
1390 }
1391 bound = t.mapRect(bound);
1392 bound.moveRight(plotRect().left() - _calculatedAxisMarginHLead);
1393 bound.moveTop(top);
1394 } else if (rotation > 0) {
1395 qreal theta = (rotation <45.0) ? rotation : 45.0;
1396 qreal bottom;
1397 if (rotation < 89) {
1398 bottom = mapYToPlot(yLabelIt.key()) + bound.height()*0.5*cos(theta*2.0*M_PI/180.0);
1399 } else {
1400 bottom = mapYToPlot(yLabelIt.key()) + bound.width()*0.5;
1401 }
1402 bound = t.mapRect(bound);
1403 bound.moveRight(plotRect().left() - _calculatedAxisMarginHLead);
1404 bound.moveBottom(bottom);
1405 } else { // no rotation.
1406 p = QPointF(plotRect().left() - _calculatedAxisMarginHLead,
1407 mapYToPlot(yLabelIt.key()) - bound.height() * 0.5);
1408 bound.moveTopRight(p);
1409 }
1410
1411 if (rect().top() > bound.top()) bound.setTop(rect().top());
1412 if (rect().bottom() < bound.bottom()) bound.setBottom(rect().bottom());
1413
1414 CachedPlotLabel label;
1415 label.bound = bound;
1416 label.value = yLabelIt.value();
1417 _yPlotLabels.append(label);
1418 }
1419
1420 if (!_yAxis->baseLabel().isEmpty()) {
1421 painter->save();
1422 painter->rotate(-90.0);
1423
1424 QRectF bound = painter->boundingRect(QRectF(), flags, _yAxis->baseLabel());
1425 bound = QRectF(bound.x(), bound.bottomRight().y() - bound.width(), bound.height(), bound.width());
1426 QPointF p = QPointF(rect().left() + _calculatedLeftBaseOffset, plotRect().bottom());
1427 bound.moveBottomLeft(p);
1428
1429 CachedPlotLabel label;
1430 label.bound = bound;
1431 label.value = _yAxis->baseLabel();
1432 label.baseLabel = true;
1433 _yPlotLabels.append(label);
1434 painter->restore();
1435 }
1436 }
1437
1438
paintMajorGridLines(QPainter * painter)1439 void PlotItem::paintMajorGridLines(QPainter *painter) {
1440 if (xAxis()->drawAxisMajorGridLines()) {
1441 painter->save();
1442 painter->setPen(QPen(QBrush(_xAxis->axisMajorGridLineColor()),
1443 Curve::lineDim(painter->window(),_xAxis->axisMajorGridLineWidth()),
1444 _xAxis->axisMajorGridLineStyle()));
1445 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1446 painter->drawLines(_xMajorGridLines);
1447 painter->restore();
1448 }
1449
1450 if (yAxis()->drawAxisMajorGridLines()) {
1451 painter->save();
1452 painter->setPen(QPen(QBrush(_yAxis->axisMajorGridLineColor()),
1453 Curve::lineDim(painter->window(),_yAxis->axisMajorGridLineWidth()),
1454 _yAxis->axisMajorGridLineStyle()));
1455 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1456 painter->drawLines(_yMajorGridLines);
1457 painter->restore();
1458 }
1459 }
1460
1461
paintMinorGridLines(QPainter * painter)1462 void PlotItem::paintMinorGridLines(QPainter *painter) {
1463 if (xAxis()->drawAxisMinorGridLines()) {
1464 painter->save();
1465 painter->setPen(QPen(QBrush(_xAxis->axisMinorGridLineColor()),
1466 Curve::lineDim(painter->window(),_xAxis->axisMinorGridLineWidth()),
1467 _xAxis->axisMinorGridLineStyle()));
1468 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1469 painter->drawLines(_xMinorGridLines);
1470 painter->restore();
1471 }
1472
1473 if (yAxis()->drawAxisMinorGridLines()) {
1474 painter->save();
1475 painter->setPen(QPen(QBrush(_yAxis->axisMinorGridLineColor()),
1476 Curve::lineDim(painter->window(),_yAxis->axisMinorGridLineWidth()),
1477 _yAxis->axisMinorGridLineStyle()));
1478 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1479 painter->drawLines(_yMinorGridLines);
1480 painter->restore();
1481 }
1482 }
1483
1484
paintMajorTicks(QPainter * painter)1485 void PlotItem::paintMajorTicks(QPainter *painter) {
1486 painter->save();
1487 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1488 if (xAxis()->drawAxisMajorTicks()) {
1489 painter->drawLines(_xMajorTickLines);
1490 }
1491
1492 if (yAxis()->drawAxisMajorTicks()) {
1493 painter->drawLines(_yMajorTickLines);
1494 }
1495 painter->restore();
1496 }
1497
1498
paintMinorTicks(QPainter * painter)1499 void PlotItem::paintMinorTicks(QPainter *painter) {
1500 painter->save();
1501 painter->setRenderHint(QPainter::Antialiasing, ApplicationSettings::self()->antialiasPlots());
1502 if (xAxis()->drawAxisMinorTicks()) {
1503 painter->drawLines(_xMinorTickLines);
1504 }
1505
1506 if (yAxis()->drawAxisMinorTicks()) {
1507 painter->drawLines(_yMinorTickLines);
1508 }
1509 painter->restore();
1510 }
1511
1512
scaleAxisLabels(qreal scaleFactor)1513 void PlotItem::scaleAxisLabels(qreal scaleFactor) {
1514 _numberAxisLabelScaleFactor = qMin(_numberAxisLabelScaleFactor, scaleFactor);
1515 }
1516
1517
resetScaleAxisLabels()1518 void PlotItem::resetScaleAxisLabels() {
1519 _numberAxisLabelScaleFactor = 1.0;
1520 }
1521
1522
isUseAxisScale() const1523 bool PlotItem::isUseAxisScale() const {
1524 return _useNumberAxisLabelScale;
1525 }
1526
1527
setUseAxisScale(bool useScale)1528 void PlotItem::setUseAxisScale(bool useScale) {
1529 if (_useNumberAxisLabelScale != useScale) {
1530 _useNumberAxisLabelScale = useScale;
1531 setPlotPixmapDirty();
1532 }
1533 }
1534
1535
PaintNumber(QPainter * painter,const QRectF rec,int flags,const QString & text)1536 static void PaintNumber(QPainter *painter, const QRectF rec, int flags, const QString &text) {
1537 const double superscript_scale = 0.60;
1538 const double superscript_raise = 0.44;
1539 QRectF r = rec;
1540 QStringList base_mantisa = text.split('e');
1541
1542 if (base_mantisa.size()>1) {
1543 if (base_mantisa[1][0].isLetter()) {
1544 base_mantisa.clear();
1545 base_mantisa.append(text);
1546 }
1547 }
1548
1549
1550 if (base_mantisa.size()<=1) {
1551 painter->drawText(r, flags, text);
1552 } else {
1553 QString base;
1554 if (base_mantisa[0]==QString('x')) {
1555 base = "10";
1556 base_mantisa[0].clear();
1557 } else {
1558 base = "x10";
1559 }
1560 base_mantisa[1].remove('+');
1561 if (base_mantisa[1].contains(']')) {
1562 base_mantisa[1].remove(']');
1563 base_mantisa.append(QString(']'));
1564 }
1565 qreal w = painter->fontMetrics().width(base_mantisa[0] + base) +
1566 painter->fontMetrics().width(base_mantisa[1])*superscript_scale;
1567 if (base_mantisa.size()>2) {
1568 w += painter->fontMetrics().width(base_mantisa[2]);
1569 }
1570 if (flags & Qt::AlignRight) {
1571 qreal right = r.right();
1572 r.setWidth(w);
1573 r.moveRight(right);
1574 } else if (flags & Qt::AlignCenter) {
1575 QPointF center = r.center();
1576 r.setWidth(w);
1577 r.moveCenter(center);
1578 }
1579 QPointF p = QPointF(r.topLeft().x(), r.center().y()+painter->fontMetrics().boundingRect('0').height()/2);
1580 //painter->drawRect(r);
1581 painter->drawText(p, base_mantisa[0]);
1582 p.setX(p.x() + painter->fontMetrics().width(base_mantisa[0]));
1583 painter->drawText(p,base);
1584 qreal ly = p.y();
1585 p.setX(p.x() + painter->fontMetrics().width(base));
1586 p.setY(p.y() - superscript_raise * painter->fontMetrics().height());
1587 painter->save();
1588 QFont f = painter->font();
1589 f.setPointSizeF(f.pointSizeF()*superscript_scale);
1590 painter->setFont(f);
1591 painter->drawText(p,base_mantisa[1]);
1592 p.setX(p.x() + painter->fontMetrics().width(base_mantisa[1]));
1593 painter->restore();
1594 if (base_mantisa.size()>2) {
1595 p.setY(ly);
1596 painter->drawText(p,base_mantisa[2]);
1597 }
1598 }
1599 }
1600
paintBottomTickLabels(QPainter * painter)1601 void PlotItem::paintBottomTickLabels(QPainter *painter) {
1602 int flags = Qt::TextSingleLine/* | Qt::AlignCenter*/;
1603
1604 painter->save();
1605 painter->setPen(_numberLabelDetails->fontColor());
1606
1607 int rotation = _xAxis->axisLabelRotation();
1608 foreach(const CachedPlotLabel &label, _xPlotLabels) {
1609 QRectF bound = label.bound;
1610 if (_numberAxisLabelScaleFactor<0.9999) {
1611 bound.translate( bound.width() *(1.0-_numberAxisLabelScaleFactor)*0.5, 0.0);
1612 }
1613 if (rotation != 0) {
1614 painter->save();
1615 QTransform t;
1616 t.rotate(-1*rotation);
1617 painter->rotate(rotation);
1618
1619 PaintNumber(painter, t.mapRect(bound), Qt::TextSingleLine | Qt::AlignCenter, label.value);
1620 painter->restore();
1621 } else {
1622 PaintNumber(painter, bound, flags, label.value);
1623 }
1624 }
1625 painter->restore();
1626
1627 }
1628
1629
paintLeftTickLabels(QPainter * painter)1630 void PlotItem::paintLeftTickLabels(QPainter *painter) {
1631 int flags = Qt::TextSingleLine | Qt::AlignVCenter | Qt::AlignRight;
1632
1633 painter->save();
1634 painter->setPen(_numberLabelDetails->fontColor());
1635
1636 int rotation = _yAxis->axisLabelRotation();
1637
1638 foreach(const CachedPlotLabel &label, _yPlotLabels) {
1639 if (label.baseLabel) {
1640 painter->save();
1641 QTransform t;
1642 t.rotate(90.0);
1643 painter->rotate(-90.0);
1644
1645 PaintNumber(painter, t.mapRect(label.bound), flags, label.value);
1646 //painter->drawText(t.mapRect(label.bound), flags, label.value);
1647 painter->restore();
1648 } else {
1649 if (rotation != 0) {
1650 painter->save();
1651 QTransform t;
1652 t.rotate(-1*rotation);
1653 painter->rotate(rotation);
1654
1655 PaintNumber(painter, t.mapRect(label.bound), flags, label.value);
1656 //painter->drawText(t.mapRect(label.bound), flags, label.value);
1657 painter->restore();
1658 } else {
1659 PaintNumber(painter, label.bound, flags, label.value);
1660 //painter->drawText(label.bound, flags, label.value);
1661 }
1662 }
1663 }
1664 painter->restore();
1665
1666 #if DEBUG_LABEL_REGION
1667 QRectF yLabelRect;
1668 foreach(const CachedPlotLabel &label, _yPlotLabels) {
1669 if (yLabelRect.isValid()) {
1670 yLabelRect = yLabelRect.united(label.bound);
1671 } else {
1672 yLabelRect = label.bound;
1673 }
1674 }
1675 painter->save();
1676 painter->setOpacity(0.3);
1677 qDebug() << "Left Tick Labels - yLabelRect:" << yLabelRect;
1678 painter->fillRect(yLabelRect, Qt::green);
1679 painter->restore();
1680 #endif
1681 }
1682
1683
paintTickLabels(QPainter * painter)1684 void PlotItem::paintTickLabels(QPainter *painter) {
1685 if (_xAxis->isAxisVisible()) {
1686 paintBottomTickLabels(painter);
1687 }
1688 if (_yAxis->isAxisVisible()) {
1689 paintLeftTickLabels(painter);
1690 }
1691 }
1692
1693
paintPlotMarkers(QPainter * painter)1694 void PlotItem::paintPlotMarkers(QPainter *painter) {
1695 if (!_xPlotMarkerLines.isEmpty()) {
1696 painter->save();
1697 painter->setPen(QPen(QBrush(_xAxis->axisPlotMarkers().lineColor()),
1698 Curve::lineDim(painter->window(),_xAxis->axisPlotMarkers().lineWidth()),
1699 _xAxis->axisPlotMarkers().lineStyle()));
1700 painter->drawLines(_xPlotMarkerLines);
1701 painter->restore();
1702 }
1703 if (!_yPlotMarkerLines.isEmpty()) {
1704 painter->save();
1705 painter->setPen(QPen(QBrush(_yAxis->axisPlotMarkers().lineColor()),
1706 Curve::lineDim(painter->window(),_yAxis->axisPlotMarkers().lineWidth()),
1707 _yAxis->axisPlotMarkers().lineStyle()));
1708 painter->drawLines(_yPlotMarkerLines);
1709 painter->restore();
1710 }
1711 }
1712
1713
calculatePlotRects()1714 void PlotItem::calculatePlotRects() {
1715 // Calculate the plotAxisRect first.
1716 qreal left = _leftLabelDetails->isVisible() ? leftLabelMargin() : 0.0;
1717 qreal bottom = _bottomLabelDetails->isVisible() ? bottomLabelMargin() : 0.0;
1718 qreal right = _rightLabelDetails->isVisible() ? rightMarginSize() : 0.0;
1719 qreal top = _topLabelDetails->isVisible() ? topMarginSize() : 0.0;
1720
1721 QPointF topLeft(rect().topLeft() + QPointF(left, top));
1722 if (_manuallyHideRightAxisLabel && !_isInSharedAxisBox) {
1723 right += 1;
1724 }
1725 if (_manuallyHideBottomAxisLabel && !_isInSharedAxisBox) {
1726 bottom += 1;
1727 }
1728 QPointF bottomRight(rect().bottomRight() - QPointF(right, bottom));
1729
1730 _calculatedPlotAxisRect = QRectF(topLeft, bottomRight);
1731
1732 // Use the PlotAxisRect as basis to calculate PlotRect.
1733 QRectF plot = _calculatedPlotAxisRect;
1734 qreal xOffset = _xAxis->isAxisVisible() ? axisMarginHeight() : 0.0;
1735 qreal yOffset = _yAxis->isAxisVisible() ? axisMarginWidth() : 0.0;
1736 qreal bottomPadding = _xAxis->isAxisVisible() ? _bottomPadding : 0.0;
1737 qreal leftPadding = _yAxis->isAxisVisible() ? _leftPadding : 0.0;
1738 qreal rightPadding = _rightLabelDetails->isVisible() ? _rightPadding : 0.0;
1739 qreal topPadding = _topLabelDetails->isVisible() ? _topPadding : 0.0;
1740
1741 plot.setLeft(plot.left() + yOffset + leftPadding);
1742 plot.setBottom(plot.bottom() - xOffset - bottomPadding);
1743 plot.setRight(plot.right() - rightPadding);
1744 plot.setTop(plot.top() + topPadding);
1745 if (!plot.isValid()) {
1746 if (plot.width() <= 0) {
1747 plot.setWidth(0.1);
1748 }
1749 if (plot.height() <= 0) {
1750 plot.setHeight(0.1);
1751 }
1752 }
1753 _calculatedPlotRect = plot;
1754 _plotRectsDirty = false;
1755 emit updatePlotRect();
1756 }
1757
1758
plotAxisRect()1759 QRectF PlotItem::plotAxisRect() {
1760 if (_plotRectsDirty) {
1761 calculatePlotRects();
1762 }
1763 return _calculatedPlotAxisRect;
1764 }
1765
1766
plotRect()1767 QRectF PlotItem::plotRect() {
1768 if (_plotRectsDirty) {
1769 calculatePlotRects();
1770 }
1771 return _calculatedPlotRect;
1772 }
1773
1774
leftMarginSize() const1775 qreal PlotItem::leftMarginSize() const {
1776 qreal margin = _leftLabelDetails->isVisible() ? leftLabelMargin() : 0.0;
1777 margin += _yAxis->isAxisVisible() ? axisMarginWidth() : 0.0;
1778
1779 return margin;
1780 }
1781
1782
bottomMarginSize() const1783 qreal PlotItem::bottomMarginSize() const {
1784 qreal margin = _bottomLabelDetails->isVisible() ? bottomLabelMargin() : 0.0;
1785 margin += _xAxis->isAxisVisible() ? axisMarginHeight() : 0.0;
1786
1787 return margin;
1788 }
1789
1790
rightMarginSize() const1791 qreal PlotItem::rightMarginSize() const {
1792 qreal margin = _rightLabelDetails->isVisible() ? rightLabelMargin() : 0.0;
1793 if (supportsTiedZoom() && margin < tiedZoomSize().width()) margin = tiedZoomSize().width();
1794 return margin;
1795 }
1796
1797
topMarginSize() const1798 qreal PlotItem::topMarginSize() const {
1799 qreal margin = _topLabelDetails->isVisible() ? topLabelMargin() : 0.0;
1800 if (supportsTiedZoom() && margin < tiedZoomSize().height()) margin = tiedZoomSize().height();
1801 return margin;
1802 }
1803
1804
setPadding(const qreal left,const qreal right,const qreal top,const qreal bottom)1805 void PlotItem::setPadding(const qreal left, const qreal right, const qreal top, const qreal bottom) {
1806 if ((left == _leftPadding) && (right == _rightPadding) && (top == _topPadding) && (bottom == _bottomPadding)) {
1807 return;
1808 }
1809 _leftPadding = left;
1810 _rightPadding = right;
1811 _topPadding = top;
1812 _bottomPadding = bottom;
1813 setPlotRectsDirty();
1814 emit triggerRedraw();
1815 }
1816
1817
setLeftPadding(const qreal padding)1818 void PlotItem::setLeftPadding(const qreal padding) {
1819 if (padding != _leftPadding) {
1820 _leftPadding = padding;
1821 setPlotRectsDirty();
1822 }
1823 }
1824
1825
setBottomPadding(const qreal padding)1826 void PlotItem::setBottomPadding(const qreal padding) {
1827 if (padding != _bottomPadding) {
1828 _bottomPadding = padding;
1829 setPlotRectsDirty();
1830 }
1831 }
1832
1833
setRightPadding(const qreal padding)1834 void PlotItem::setRightPadding(const qreal padding) {
1835 if (padding != _rightPadding) {
1836 _rightPadding = padding;
1837 setPlotRectsDirty();
1838 }
1839 }
1840
1841
setTopPadding(const qreal padding)1842 void PlotItem::setTopPadding(const qreal padding) {
1843 if (padding != _topPadding) {
1844 _topPadding = padding;
1845 setPlotRectsDirty();
1846 }
1847 }
1848
setManuallyHideLeftAxisLabel(bool hide)1849 void PlotItem::setManuallyHideLeftAxisLabel(bool hide) {
1850 _manuallyHideLeftAxisLabel = hide;
1851 if (!_isInSharedAxisBox) {
1852 setLeftSuppressed(hide);
1853 }
1854 }
1855
setManuallyHideRightAxisLabel(bool hide)1856 void PlotItem::setManuallyHideRightAxisLabel(bool hide) {
1857 _manuallyHideRightAxisLabel = hide;
1858 if (!_isInSharedAxisBox) {
1859 setRightSuppressed(hide);
1860 }
1861 }
1862
setManuallyHideTopAxisLabel(bool hide)1863 void PlotItem::setManuallyHideTopAxisLabel(bool hide) {
1864 _manuallyHideTopAxisLabel = hide;
1865 if (!_isInSharedAxisBox) {
1866 setTopSuppressed(hide);
1867 }
1868 }
1869
setManuallyHideBottomAxisLabel(bool hide)1870 void PlotItem::setManuallyHideBottomAxisLabel(bool hide) {
1871 _manuallyHideBottomAxisLabel = hide;
1872 if (!_isInSharedAxisBox) {
1873 setBottomSuppressed(hide);
1874 }
1875 }
1876
1877
projectionRect() const1878 QRectF PlotItem::projectionRect() const {
1879 return _projectionRect;
1880 }
1881
1882
setTiedZoom(bool tiedXZoom,bool tiedYZoom,bool checkAllTied)1883 void PlotItem::setTiedZoom(bool tiedXZoom, bool tiedYZoom, bool checkAllTied) {
1884 if ((_isXTiedZoom == tiedXZoom) && (_isYTiedZoom == tiedYZoom))
1885 return;
1886
1887 bool wasTiedZoom = isTiedZoom();
1888
1889 _isXTiedZoom = tiedXZoom;
1890 _isYTiedZoom = tiedYZoom;
1891
1892 if (isTiedZoom() && !wasTiedZoom) {
1893 PlotItemManager::self()->addTiedZoomPlot(this, checkAllTied);
1894 } else if (!isTiedZoom() && wasTiedZoom) {
1895 PlotItemManager::self()->removeTiedZoomPlot(this);
1896 }
1897
1898 //FIXME ugh, this is expensive, but need to redraw the checkboxes...
1899 update();
1900 }
1901
1902
isInSharedAxisBox() const1903 bool PlotItem::isInSharedAxisBox() const {
1904 return _isInSharedAxisBox;
1905 }
1906
1907
setInSharedAxisBox(bool inSharedBox)1908 void PlotItem::setInSharedAxisBox(bool inSharedBox) {
1909 _isInSharedAxisBox = inSharedBox;
1910 setLockParent(inSharedBox);
1911 }
1912
1913
sharedAxisBox() const1914 SharedAxisBoxItem* PlotItem::sharedAxisBox() const {
1915 return _sharedBox;
1916 }
1917
1918
setSharedAxisBox(SharedAxisBoxItem * parent)1919 void PlotItem::setSharedAxisBox(SharedAxisBoxItem* parent) {
1920 if (parent) {
1921 if (isTiedZoom()) {
1922 setTiedZoom(false, false);
1923 }
1924 setInSharedAxisBox(true);
1925 setAllowedGripModes(0);
1926 setFlags(0);
1927 setParentViewItem(parent);
1928 setBrush(Qt::transparent);
1929
1930 _sharedBox = parent;
1931 createSharedAxisBoxMenu();
1932 } else {
1933 setSupportsTiedZoom(true);
1934 setInSharedAxisBox(false);
1935 setAllowedGripModes(Move | Resize | Rotate);
1936 setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
1937 setParentViewItem(0);
1938 setBrush(Qt::white);
1939
1940 _sharedBox = 0;
1941 }
1942 }
1943
1944
setPlotBordersDirty(bool dirty)1945 void PlotItem::setPlotBordersDirty(bool dirty) {
1946 if (isInSharedAxisBox() && dirty && _sharedBox) {
1947 _sharedBox->setDirty();
1948 } else {
1949 view()->setPlotBordersDirty(dirty);
1950 }
1951 if (dirty) {
1952 setPlotRectsDirty();
1953 }
1954 }
1955
1956
updateScale()1957 void PlotItem::updateScale() {
1958 if (_xAxis->axisLog()) {
1959 _xMax = logXHi(projectionRect().right());
1960 _xMin = logXLo(projectionRect().left());
1961 } else {
1962 _xMax = projectionRect().right();
1963 _xMin = projectionRect().left();
1964 }
1965
1966 if (_yAxis->axisLog()) {
1967 _yMax = logYHi(projectionRect().bottom());
1968 _yMin = logYLo(projectionRect().top());
1969 } else {
1970 _yMax = projectionRect().bottom();
1971 _yMin = projectionRect().top();
1972 }
1973 }
1974
1975
mapToProjection(const QRectF & rect)1976 QRectF PlotItem::mapToProjection(const QRectF &rect) {
1977 QRectF projRect;
1978
1979 // Invert and convert points.
1980 QPointF topLeft;
1981 QPointF bottomRight;
1982 if (!(_xAxis->axisReversed() || _yAxis->axisReversed())) {
1983 topLeft = mapToProjection(rect.bottomLeft());
1984 bottomRight = mapToProjection(rect.topRight());
1985 } else if (_xAxis->axisReversed() && _yAxis->axisReversed()) {
1986 topLeft = mapToProjection(rect.topRight());
1987 bottomRight = mapToProjection(rect.bottomLeft());
1988 } else if (_yAxis->axisReversed()) {
1989 topLeft = mapToProjection(rect.topLeft());
1990 bottomRight = mapToProjection(rect.bottomRight());
1991 } else {
1992 topLeft = mapToProjection(rect.bottomRight());
1993 bottomRight = mapToProjection(rect.topLeft());
1994 }
1995
1996 projRect.setTopLeft(topLeft);
1997
1998 projRect.setWidth(bottomRight.x() - topLeft.x());
1999 projRect.setHeight(bottomRight.y() - topLeft.y());
2000
2001 return projRect;
2002 }
2003
2004
mapToProjection(const QPointF & point)2005 QPointF PlotItem::mapToProjection(const QPointF &point) {
2006 QRectF pr = plotRect();
2007 double xpos, ypos;
2008
2009 updateScale();
2010
2011 if (_xAxis->axisReversed()) {
2012 xpos = (double)(pr.right() - point.x())/(double)pr.width();
2013 } else {
2014 xpos = (double)(point.x() - pr.left())/(double)pr.width();
2015 }
2016 xpos = xpos * (_xMax - _xMin) + _xMin;
2017
2018 if (_xAxis->axisLog()) {
2019 xpos = pow(10, xpos);
2020 }
2021
2022 if (_yAxis->axisReversed()) {
2023 ypos = (double)(point.y() - pr.top())/(double)pr.height();
2024 } else {
2025 ypos = (double)(pr.bottom() - point.y())/(double)pr.height();
2026 }
2027 ypos = ypos * (_yMax - _yMin) + _yMin;
2028
2029 if (_yAxis->axisLog()) {
2030 ypos = pow(10, ypos);
2031 }
2032
2033 return QPointF(xpos, ypos);
2034 }
2035
2036
mapToPlot(const QPointF & point)2037 QPointF PlotItem::mapToPlot(const QPointF &point) {
2038 return QPointF(mapXToPlot(point.x()), mapYToPlot(point.y()));
2039 }
2040
2041
mapXToPlot(const qreal & x)2042 qreal PlotItem::mapXToPlot(const qreal &x) {
2043 QRectF pr = plotRect();
2044 double newX = x;
2045
2046 if (_xAxis->axisLog()) {
2047 newX = logXLo(x);
2048 }
2049
2050 newX -= _xMin;
2051 newX = newX / (_xMax - _xMin);
2052
2053 newX = newX * pr.width();
2054
2055 if (_xAxis->axisLog() && x == -350) {
2056 newX = 0;
2057 }
2058
2059 if (_xAxis->axisReversed()) {
2060 newX = pr.right() - newX;
2061 } else {
2062 newX = newX + pr.left();
2063 }
2064 return newX;
2065 }
2066
2067
mapYToPlot(const qreal & y)2068 qreal PlotItem::mapYToPlot(const qreal &y) {
2069 QRectF pr = plotRect();
2070 double newY = y;
2071
2072 if (_yAxis->axisLog()) {
2073 newY = logYLo(y);
2074 }
2075
2076 newY -= _yMin;
2077 newY = newY / (_yMax - _yMin);
2078
2079 newY = newY * pr.height();
2080
2081 if (_yAxis->axisLog() && y == -350) {
2082 newY = 0;
2083 }
2084
2085 if (_yAxis->axisReversed()) {
2086 newY = newY + pr.top();
2087 } else {
2088 newY = pr.bottom() - newY;
2089 }
2090 return newY;
2091 }
2092
2093
globalFont() const2094 QFont PlotItem::globalFont() const {
2095 return _globalFont;
2096 }
2097
2098
setGlobalFont(const QFont & font)2099 void PlotItem::setGlobalFont(const QFont &font) {
2100 if (font != _globalFont) {
2101 _globalFont = font;
2102 setPlotBordersDirty(true);
2103 setLabelsDirty();
2104 }
2105 }
2106
2107
globalFontScale() const2108 qreal PlotItem::globalFontScale() const {
2109 return _globalFontScale;
2110 }
2111
2112
setGlobalFontScale(const qreal scale)2113 void PlotItem::setGlobalFontScale(const qreal scale) {
2114 if (scale != _globalFontScale) {
2115 _globalFontScale = scale;
2116 setPlotBordersDirty(true);
2117 setLabelsDirty();
2118 }
2119 }
2120
2121
globalFontColor() const2122 QColor PlotItem::globalFontColor() const {
2123 return _globalFontColor;
2124 }
2125
2126
setGlobalFontColor(const QColor & color)2127 void PlotItem::setGlobalFontColor(const QColor &color) {
2128 if (color != _globalFontColor) {
2129 _globalFontColor = color;
2130 setLabelsDirty();
2131 }
2132 }
2133
2134
leftLabel() const2135 QString PlotItem::leftLabel() const {
2136 if (!leftLabelDetails()->isAuto()) {
2137 return leftLabelDetails()->text();
2138 } else {
2139 return autoLeftLabel();
2140 }
2141 }
2142
2143
autoLeftLabel() const2144 QString PlotItem::autoLeftLabel() const {
2145 foreach (PlotRenderItem *renderer, renderItems()) {
2146 QString label = renderer->leftLabel();
2147 if (!label.isEmpty()) {
2148 if (_yAxis->axisInterpret()) { // remove units
2149 QRegExp rx(" \\[*\\]");
2150 rx.setPatternSyntax(QRegExp::Wildcard);
2151 return label.remove(rx);
2152 } else {
2153 return label;
2154 }
2155 }
2156 }
2157 return QString();
2158 }
2159
2160
bottomLabel() const2161 QString PlotItem::bottomLabel() const {
2162 if (!bottomLabelDetails()->isAuto()) {
2163 return bottomLabelDetails()->text();
2164 } else {
2165 return autoBottomLabel();
2166 }
2167 }
2168
2169
autoBottomLabel() const2170 QString PlotItem::autoBottomLabel() const {
2171 foreach (PlotRenderItem *renderer, renderItems()) {
2172 QString label = renderer->bottomLabel();
2173 if (!label.isEmpty()) {
2174 if (_xAxis->axisInterpret()) { // remove units if time interpretation
2175 QRegExp rx(" \\[*\\]");
2176 rx.setPatternSyntax(QRegExp::Wildcard);
2177 return label.remove(rx);
2178 } else {
2179 return label;
2180 }
2181 }
2182 }
2183 return QString();
2184 }
2185
2186
rightLabel() const2187 QString PlotItem::rightLabel() const {
2188 if (!rightLabelDetails()->isAuto()) {
2189 return rightLabelDetails()->text();
2190 } else {
2191 return autoRightLabel();
2192 }
2193 }
2194
2195
autoRightLabel() const2196 QString PlotItem::autoRightLabel() const {
2197 foreach (PlotRenderItem *renderer, renderItems()) {
2198 QString label = renderer->rightLabel();
2199 if (!label.isEmpty())
2200 return label;
2201 }
2202 return QString();
2203 }
2204
2205
topLabel() const2206 QString PlotItem::topLabel() const {
2207 if (!topLabelDetails()->isAuto()) {
2208 return topLabelDetails()->text();
2209 } else {
2210 return autoTopLabel();
2211 }
2212 }
2213
2214
autoTopLabel() const2215 QString PlotItem::autoTopLabel() const {
2216 if (showLegend()) {
2217 return QString();
2218 } else {
2219 QString label;
2220 int count = renderItems().count();
2221 for (int i=0; i<count; i++) {
2222 label += renderItems().at(i)->topLabel();
2223 if (i<count - 1) {
2224 label += ' ';
2225 }
2226 }
2227 if (label == leftLabel()) {
2228 return QString();
2229 } else {
2230 return label;
2231 }
2232 }
2233 }
2234
2235
setTopSuppressed(bool suppressed)2236 void PlotItem::setTopSuppressed(bool suppressed) {
2237 if (!_isInSharedAxisBox) {
2238 if (_manuallyHideTopAxisLabel) {
2239 suppressed = true;
2240 }
2241 }
2242 _topLabelDetails->setVisible(!suppressed);
2243 }
2244
2245
setRightSuppressed(bool suppressed)2246 void PlotItem::setRightSuppressed(bool suppressed) {
2247 if (!_isInSharedAxisBox) {
2248 if (_manuallyHideRightAxisLabel) {
2249 suppressed = true;
2250 }
2251 }
2252 _rightLabelDetails->setVisible(!suppressed);
2253 }
2254
2255
setLeftSuppressed(bool suppressed)2256 void PlotItem::setLeftSuppressed(bool suppressed) {
2257 if (!_isInSharedAxisBox) {
2258 if (_manuallyHideLeftAxisLabel) {
2259 suppressed = true;
2260 }
2261 }
2262 _leftLabelDetails->setVisible(!suppressed);
2263 _yAxis->setAxisVisible(!suppressed);
2264 }
2265
2266
setBottomSuppressed(bool suppressed)2267 void PlotItem::setBottomSuppressed(bool suppressed) {
2268 if (!_isInSharedAxisBox) {
2269 if (_manuallyHideBottomAxisLabel) {
2270 suppressed = true;
2271 }
2272 }
2273 _bottomLabelDetails->setVisible(!suppressed);
2274 _xAxis->setAxisVisible(!suppressed);
2275 }
2276
2277
setLabelsVisible(bool visible)2278 void PlotItem::setLabelsVisible(bool visible) {
2279 _leftLabelDetails->setVisible(visible);
2280 _rightLabelDetails->setVisible(visible);
2281 _topLabelDetails->setVisible(visible);
2282 _bottomLabelDetails->setVisible(visible);
2283 _xAxis->setAxisVisible(visible);
2284 _yAxis->setAxisVisible(visible);
2285 }
2286
2287
labelMarginWidth() const2288 qreal PlotItem::labelMarginWidth() const {
2289 return _calculatedLabelMarginWidth;
2290 }
2291
2292
leftLabelMargin() const2293 qreal PlotItem::leftLabelMargin() const {
2294 return _calculatedLeftLabelMargin;
2295 }
2296
2297
rightLabelMargin() const2298 qreal PlotItem::rightLabelMargin() const {
2299 return _calculatedRightLabelMargin;
2300 }
2301
2302
labelMarginHeight() const2303 qreal PlotItem::labelMarginHeight() const {
2304 return _calculatedLabelMarginHeight;
2305 }
2306
2307
topLabelMargin() const2308 qreal PlotItem::topLabelMargin() const {
2309 return _calculatedTopLabelMargin;
2310 }
2311
2312
2313
bottomLabelMargin() const2314 qreal PlotItem::bottomLabelMargin() const {
2315 return _calculatedBottomLabelMargin;
2316 }
2317
2318
topLabelRect() const2319 QRectF PlotItem::topLabelRect() const {
2320 if (topLabelMargin()>0) {
2321 return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), topLabelMargin());
2322 } else {
2323 return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), _calculatedTopLabelHeight);
2324 }
2325 }
2326
2327
bottomLabelRect() const2328 QRectF PlotItem::bottomLabelRect() const {
2329 return QRectF(0.0, 0.0, width() - leftLabelMargin() - rightLabelMargin(), bottomLabelMargin());
2330 }
2331
2332
leftLabelRect() const2333 QRectF PlotItem::leftLabelRect() const {
2334 return QRectF(0.0, 0.0, leftLabelMargin(), height() - topLabelMargin() - bottomLabelMargin());
2335 }
2336
2337
rightLabelRect() const2338 QRectF PlotItem::rightLabelRect() const {
2339 return QRectF(0.0, 0.0, rightLabelMargin(), height() - topLabelMargin() - bottomLabelMargin());
2340 }
2341
2342
generateLeftLabel(QPainter * p)2343 void PlotItem::generateLeftLabel(QPainter *p) {
2344 if (!_leftLabel.dirty) {
2345 return;
2346 }
2347 _leftLabel.valid = false;
2348 _leftLabel.dirty = false;
2349 Label::Parsed *parsed = Label::parse(leftLabel(), _leftLabelDetails->fontColor());
2350 if (parsed) {
2351
2352 if (_leftLabel.rc) {
2353 delete _leftLabel.rc;
2354 }
2355
2356 Label::RenderContext *rc = new Label::RenderContext(leftLabelDetails()->calculatedFont(*p->device()), p);
2357 rc->y = rc->fontAscent();
2358 Label::renderLabel(*rc, parsed->chunk, true, false);
2359
2360 QTransform t;
2361 t.translate(rect().left(),plotRect().center().y() + rc->x/2);
2362 t.rotate(-90.0);
2363
2364 connect(rc, SIGNAL(labelDirty()), this, SLOT(setLeftLabelDirty()));
2365 connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2366
2367 _leftLabel.rc = rc;
2368 _leftLabel.transform = t;
2369 _leftLabel.valid = true;
2370
2371 delete parsed;
2372 }
2373 }
2374
2375
paintLeftLabel(QPainter * painter)2376 void PlotItem::paintLeftLabel(QPainter *painter) {
2377 if (!_leftLabelDetails->isVisible() || leftLabel().isEmpty())
2378 return;
2379
2380 generateLeftLabel(painter);
2381
2382 if (_leftLabel.valid) {
2383 painter->save();
2384 painter->setTransform(_leftLabel.transform, true);
2385 Label::paintLabel(*_leftLabel.rc, painter);
2386 painter->restore();
2387 }
2388 }
2389
2390
calculateLeftLabelMargin(QPainter * painter)2391 void PlotItem::calculateLeftLabelMargin(QPainter *painter) {
2392 if (!_leftLabelDetails->isVisible()) {
2393 _calculatedLeftLabelMargin = 0;
2394 } else {
2395 painter->save();
2396 QTransform t;
2397 t.rotate(90.0);
2398 painter->rotate(-90.0);
2399
2400 painter->setFont(leftLabelDetails()->calculatedFont(*painter->device()));
2401 QRectF leftLabelBound = painter->boundingRect(t.mapRect(leftLabelRect()),
2402 Qt::AlignCenter, leftLabel());
2403 painter->restore();
2404
2405 _calculatedLeftLabelMargin = leftLabelBound.height();
2406 _calculatedLeftLabelWidth = leftLabelBound.width();
2407
2408 //No more than 1/4 the width of the plot
2409 if (width() < _calculatedLeftLabelMargin * 4)
2410 _calculatedLeftLabelMargin = width() / 4;
2411 }
2412 }
2413
2414
generateBottomLabel(QPainter * p)2415 void PlotItem::generateBottomLabel(QPainter *p) {
2416 if (!_bottomLabel.dirty) {
2417 return;
2418 }
2419
2420 _bottomLabel.valid = false;
2421 _bottomLabel.dirty = false;
2422 Label::Parsed *parsed = Label::parse(bottomLabel(),_bottomLabelDetails->fontColor());
2423 if (parsed) {
2424
2425 if (_bottomLabel.rc) {
2426 delete _bottomLabel.rc;
2427 }
2428
2429 Label::RenderContext *rc = new Label::RenderContext(bottomLabelDetails()->calculatedFont(*p->device()), p);
2430 rc->y = rc->fontAscent();
2431 Label::renderLabel(*rc, parsed->chunk, true, false);
2432
2433 QTransform t;
2434 t.translate(plotRect().center().x() - rc->x / 2, plotAxisRect().bottom());
2435
2436 connect(rc, SIGNAL(labelDirty()), this, SLOT(setBottomLabelDirty()));
2437 connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2438
2439 _bottomLabel.rc = rc;
2440 _bottomLabel.transform = t;
2441 _bottomLabel.valid = true;
2442
2443 delete parsed;
2444 }
2445 }
2446
2447
paintBottomLabel(QPainter * painter)2448 void PlotItem::paintBottomLabel(QPainter *painter) {
2449 if (!_bottomLabelDetails->isVisible() || bottomLabel().isEmpty())
2450 return;
2451
2452 generateBottomLabel(painter);
2453
2454 if (_bottomLabel.valid) {
2455 painter->save();
2456 painter->setTransform(_bottomLabel.transform, true);
2457 Label::paintLabel(*_bottomLabel.rc, painter);
2458 painter->restore();
2459 }
2460 }
2461
2462
calculateBottomLabelMargin(QPainter * painter)2463 void PlotItem::calculateBottomLabelMargin(QPainter *painter) {
2464 if (!_bottomLabelDetails->isVisible()) {
2465 _calculatedBottomLabelMargin = 0;
2466 } else {
2467 painter->save();
2468
2469 painter->setFont(bottomLabelDetails()->calculatedFont(*painter->device()));
2470
2471 QRectF bottomLabelBound = painter->boundingRect(bottomLabelRect(),
2472 Qt::AlignCenter, bottomLabel());
2473 painter->restore();
2474
2475 _calculatedBottomLabelMargin = bottomLabelBound.height();
2476 _calculatedBottomLabelWidth = bottomLabelBound.width();
2477
2478 //No more than 1/4 the height of the plot
2479 if (height() < _calculatedBottomLabelMargin * 4)
2480 _calculatedLeftLabelMargin = height() / 4;
2481 }
2482 }
2483
2484
generateRightLabel(QPainter * p)2485 void PlotItem::generateRightLabel(QPainter *p) {
2486 if (!_rightLabel.dirty) {
2487 return;
2488 }
2489 _rightLabel.valid = false;
2490 _rightLabel.dirty = false;
2491 Label::Parsed *parsed = Label::parse(rightLabel(), _rightLabelDetails->fontColor());
2492 if (parsed && rightLabelRect().isValid()) {
2493
2494 if (_rightLabel.parsed) {
2495 delete _rightLabel.parsed;
2496 }
2497
2498 Label::RenderContext *rc = new Label::RenderContext(rightLabelDetails()->calculatedFont(*p->device()), p);
2499 rc->y = rc->fontAscent();
2500 Label::renderLabel(*rc, parsed->chunk, true, false);
2501
2502 QTransform t;
2503 t.translate(rect().right(), plotRect().center().y() - rc->x/2);
2504
2505 t.rotate(90.0);
2506
2507 connect(rc, SIGNAL(labelDirty()), this, SLOT(setRightLabelDirty()));
2508 connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2509
2510 _rightLabel.rc = rc;
2511 _rightLabel.transform = t;
2512 _rightLabel.valid = true;
2513
2514 delete parsed;
2515 }
2516 }
2517
2518
paintRightLabel(QPainter * painter)2519 void PlotItem::paintRightLabel(QPainter *painter) {
2520 if (!_rightLabelDetails->isVisible() || rightLabel().isEmpty())
2521 return;
2522
2523 generateRightLabel(painter);
2524
2525 if (_rightLabel.valid) {
2526 painter->save();
2527 painter->setTransform(_rightLabel.transform, true);
2528 Label::paintLabel(*_rightLabel.rc, painter);
2529 painter->restore();
2530 }
2531
2532 }
2533
2534
calculateRightLabelMargin(QPainter * painter)2535 void PlotItem::calculateRightLabelMargin(QPainter *painter) {
2536 if (!_rightLabelDetails->isVisible()) {
2537 _calculatedRightLabelMargin = 0;
2538 } else {
2539 painter->save();
2540 QTransform t;
2541 t.rotate(-90.0);
2542 painter->rotate(90.0);
2543
2544 painter->setFont(rightLabelDetails()->calculatedFont(*painter->device()));
2545
2546 QRectF rightLabelBound = painter->boundingRect(t.mapRect(rightLabelRect()),
2547 Qt::AlignCenter, rightLabel());
2548 painter->restore();
2549
2550 _calculatedRightLabelMargin = qMax(_calculatedAxisMarginROverflow, rightLabelBound.height());
2551
2552 //No more than 1/4 the width of the plot
2553 if (width() < _calculatedRightLabelMargin * 4)
2554 _calculatedRightLabelMargin = width() / 4;
2555 }
2556 }
2557
2558
generateTopLabel(QPainter * p)2559 void PlotItem::generateTopLabel(QPainter *p) {
2560 if (!_topLabel.dirty) {
2561 return;
2562 }
2563 _topLabel.valid = false;
2564 _topLabel.dirty = false;
2565 Label::Parsed *parsed = Label::parse(topLabel(), _topLabelDetails->fontColor());
2566 if (parsed && topLabelRect().isValid()) {
2567
2568 if (_topLabel.rc) {
2569 delete _topLabel.rc;
2570 }
2571
2572 Label::RenderContext *rc = new Label::RenderContext(topLabelDetails()->calculatedFont(*p->device()), p);
2573 rc->y = rc->fontAscent();
2574 Label::renderLabel(*rc, parsed->chunk, true, false);
2575
2576 QTransform t;
2577 if (_topLabelDetails->isVisible()) {
2578 t.translate(plotRect().center().x() - rc->x / 2, rect().top());
2579 } else {
2580 t.translate(plotRect().center().x() - rc->x / 2, rect().top() + topLabelRect().height()/2);
2581 }
2582 connect(rc, SIGNAL(labelDirty()), this, SLOT(setTopLabelDirty()));
2583 connect(rc, SIGNAL(labelDirty()), this, SLOT(redrawPlot()));
2584
2585 _topLabel.rc = rc;
2586 _topLabel.transform = t;
2587 _topLabel.valid = true;
2588
2589 delete parsed;
2590 }
2591 }
2592
2593
paintTopLabel(QPainter * painter)2594 void PlotItem::paintTopLabel(QPainter *painter) {
2595 if (topLabel().isEmpty())
2596 return;
2597
2598 generateTopLabel(painter);
2599 if (_topLabel.valid) {
2600 painter->save();
2601 painter->setTransform(_topLabel.transform, true);
2602 Label::paintLabel(*_topLabel.rc, painter);
2603 painter->restore();
2604
2605 }
2606 }
2607
2608
calculateTopLabelMargin(QPainter * painter)2609 void PlotItem::calculateTopLabelMargin(QPainter *painter) {
2610
2611 painter->save();
2612
2613 painter->setFont(topLabelDetails()->calculatedFont(*painter->device()));
2614
2615 QRectF topLabelBound = painter->boundingRect(topLabelRect(),
2616 Qt::AlignCenter, topLabel());
2617
2618 painter->restore();
2619
2620 _calculatedTopLabelHeight = topLabelBound.height();
2621
2622 if (!_topLabelDetails->isVisible()) {
2623 _calculatedTopLabelMargin = 0;
2624 } else {
2625 _calculatedTopLabelMargin = qMax(_calculatedAxisMarginTOverflow, topLabelBound.height());
2626
2627 //No more than 1/4 the height of the plot
2628 if (height() < _calculatedTopLabelMargin * 4)
2629 _calculatedTopLabelMargin = height() / 4;
2630 }
2631 }
2632
2633
calculateMargins()2634 void PlotItem::calculateMargins() {
2635 qreal m = qMax(_calculatedLeftLabelMargin, _calculatedRightLabelMargin);
2636
2637 //No more than 1/4 the width of the plot
2638 if (width() < m * 4)
2639 m = width() / 4;
2640
2641 _calculatedLabelMarginWidth = m;
2642
2643 m = qMax(_calculatedTopLabelMargin, _calculatedBottomLabelMargin);
2644
2645 //No more than 1/4 the height of the plot
2646 if (height() < m * 4)
2647 m = height() / 4;
2648
2649 _calculatedLabelMarginHeight = m;
2650 }
2651
2652
axisMarginWidth() const2653 qreal PlotItem::axisMarginWidth() const {
2654 return _calculatedAxisMarginWidth;
2655 }
2656
2657
axisMarginHeight() const2658 qreal PlotItem::axisMarginHeight() const {
2659 return _calculatedAxisMarginHeight;
2660 }
2661
2662 /** This function calculates and sets three things:
2663 _calculatedAxisMarginVLead: spacing between bottom of plotRect and top of axis labels
2664 _calculatedAxisMarginROverflow: rightmost axis number extension beyond plotRect
2665 _calculatedAxisMarginHeight: the height of the axis numbers
2666 */
calculateBottomTickLabelBound(QPainter * painter)2667 void PlotItem::calculateBottomTickLabelBound(QPainter *painter) {
2668 QRectF xLabelRect;
2669
2670 painter->save();
2671
2672 painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
2673
2674
2675 int flags = Qt::TextSingleLine | Qt::AlignCenter;
2676
2677 _calculatedAxisMarginVLead = painter->fontMetrics().boundingRect('0').height()/2;
2678
2679 if (_xAxis->isAxisVisible()) {
2680 // future potential optimization: only get bounds of the rightmost label
2681 // but remember: the axis may be reversed.
2682 QMapIterator<double, QString> xLabelIt(_xAxis->axisLabels());
2683 while (xLabelIt.hasNext()) {
2684 xLabelIt.next();
2685
2686 QRectF bound = painter->boundingRect(QRectF(), flags, xLabelIt.value());
2687 QPointF p(mapXToPlot(xLabelIt.key()), plotRect().bottom() + bound.height() / 2.0 + _calculatedAxisMarginVLead);
2688 bound.moveCenter(p);
2689
2690 int rotation = _xAxis->axisLabelRotation();
2691 QTransform t;
2692 t.rotate(rotation);
2693
2694 if (rotation != 0) {
2695 bound.setHeight(t.mapRect(bound).height());
2696 }
2697
2698 if (xLabelRect.isValid()) {
2699 xLabelRect = xLabelRect.united(bound);
2700 } else {
2701 xLabelRect = bound;
2702 }
2703 }
2704 }
2705
2706 xLabelRect.setHeight(xLabelRect.height() + _calculatedAxisMarginVLead);
2707
2708 if (!_xAxis->baseLabel().isEmpty()) {
2709 qreal height = painter->boundingRect(QRectF(), flags, _xAxis->baseLabel()).height();
2710 if (painter->boundingRect(QRectF(), flags, _xAxis->baseLabel()).width() + _calculatedBottomLabelWidth/2 + xLabelRect.height()/2 > plotRect().width()/2) {
2711 height += bottomLabelMargin();
2712 }
2713 if (bottomLabelMargin() < height) {
2714 xLabelRect.setHeight(xLabelRect.height() + (height - bottomLabelMargin()));
2715 }
2716 }
2717
2718 _calculatedAxisMarginHeight = xLabelRect.height();
2719 _calculatedAxisMarginROverflow = 2*ViewItem::sizeOfGrip().width();
2720
2721 painter->restore();
2722 }
2723
2724 /** This function calculates and sets three things:
2725 _calculatedAxisMarginHLead: spacing between left of plotRect and right of axis labels
2726 _calculatedAxisMarginVOverflow: topmost axis number extension beyond plotRect
2727 _calculatedAxisMarginWidth: the width of the widest axis number
2728 */
calculateLeftTickLabelBound(QPainter * painter)2729 void PlotItem::calculateLeftTickLabelBound(QPainter *painter) {
2730 QRectF yLabelRect;
2731 int flags = Qt::TextSingleLine | Qt::AlignCenter;
2732
2733 painter->save();
2734
2735 painter->setFont(numberLabelDetails()->calculatedFont(*painter->device()));
2736
2737 _calculatedAxisMarginHLead = painter->fontMetrics().boundingRect('[').height()/2;
2738
2739 if (_yAxis->isAxisVisible()) {
2740
2741 QMapIterator<double, QString> yLabelIt(_yAxis->axisLabels());
2742 while (yLabelIt.hasNext()) {
2743 yLabelIt.next();
2744
2745 // a hacky heuristic to guess the right width of the widest number for very small scientific notation numbers.
2746 // 'label' is only used to find its width. This is not exact but seems to work.
2747 QString label = yLabelIt.value();
2748 if (label.contains("e-")) {
2749 label.append('+');
2750 }
2751
2752 QRectF bound = painter->boundingRect(QRectF(), flags, label);
2753 QPointF p(plotRect().left() - bound.width() / 2.0 - _calculatedAxisMarginHLead, mapYToPlot(yLabelIt.key()));
2754 bound.moveCenter(p);
2755
2756 int rotation = _yAxis->axisLabelRotation();
2757 QTransform t;
2758 t.rotate(rotation);
2759
2760 if (rotation != 0) {
2761 bound.setWidth(t.mapRect(bound).width());
2762 bound.setHeight(t.mapRect(bound).height());
2763 }
2764
2765 if (yLabelRect.isValid()) {
2766 yLabelRect = yLabelRect.united(bound);
2767 } else {
2768 yLabelRect = bound;
2769 }
2770 }
2771 }
2772
2773 yLabelRect.setWidth(yLabelRect.width() + _calculatedAxisMarginHLead);
2774 _calculatedLeftBaseOffset = 0.0;
2775 if (!_yAxis->baseLabel().isEmpty()) {
2776 qreal height = painter->boundingRect(QRectF(), flags, _yAxis->baseLabel()).height();
2777 if (painter->boundingRect(QRectF(), flags, _yAxis->baseLabel()).width() + _calculatedLeftLabelWidth/2 + yLabelRect.width()/2 > plotRect().height()/2) {
2778 height += leftLabelMargin();
2779 _calculatedLeftBaseOffset = leftLabelMargin();
2780 }
2781 if (leftLabelMargin() < height) {
2782 yLabelRect.setWidth(yLabelRect.width() + (height - leftLabelMargin()));
2783 }
2784 }
2785 _calculatedAxisMarginWidth = yLabelRect.width();
2786 if (yLabelRect.top() < plotRect().top()) {
2787 _calculatedAxisMarginTOverflow = qMax(ViewItem::sizeOfGrip().width(), -yLabelRect.top() + plotRect().top());
2788 } else {
2789 _calculatedAxisMarginTOverflow = ViewItem::sizeOfGrip().width();
2790 }
2791 painter->restore();
2792 }
2793
2794
showLegend() const2795 bool PlotItem::showLegend() const {
2796 return _showLegend;
2797 }
2798
2799
legend()2800 LegendItem* PlotItem::legend() {
2801 if (!_legend) {
2802 _legend = new LegendItem(this);
2803 _legend->setVisible(false);
2804 double margin = 0.025*(plotRect().width() + plotRect().height());
2805 _legend->setPos(plotRect().x() + margin, plotRect().y() + margin);
2806 _legend->updateRelativeSize();
2807 }
2808 return _legend;
2809 }
2810
2811
setShowLegend(const bool show,const bool resetFonts)2812 void PlotItem::setShowLegend(const bool show, const bool resetFonts) {
2813 if (show != _showLegend) {
2814 legend()->setVisible(show);
2815 _showLegend = show;
2816 if (show && resetFonts) {
2817 legend()->setFontScale(qMax(globalFontScale()*qreal(0.6), ApplicationSettings::self()->minimumFontSize()));
2818 }
2819 }
2820 }
2821
2822
tryShortcut(const QString & keySequence)2823 bool PlotItem::tryShortcut(const QString &keySequence) {
2824 return ViewItem::tryShortcut(keySequence);
2825 }
2826
2827
setProjectionRect(const QRectF & rect,bool forceAxisUpdate)2828 void PlotItem::setProjectionRect(const QRectF &rect, bool forceAxisUpdate) {
2829 if (!(rect.isEmpty() || !rect.isValid())) {
2830 _projectionRect = rect;
2831 setPlotBordersDirty(true);
2832 emit updateAxes();
2833 update(); //slow, but need to update everything...
2834 } else if (forceAxisUpdate) {
2835 setPlotBordersDirty(true);
2836 emit updateAxes();
2837 update(); //slow, but need to update everything...
2838 }
2839 // Need to update data relative rect for all children.
2840 foreach (PlotRenderItem *render_item, renderItems()) {
2841 QList<QGraphicsItem*> children = render_item->childItems();
2842 foreach(QGraphicsItem* child, children) {
2843 ViewItem* item = dynamic_cast<ViewItem*>(child);
2844 if (item && !item->lockPosToData()) {
2845 item->updateDataRelativeRect();
2846 } else {
2847 item->applyDataLockedDimensions();
2848 }
2849 }
2850 }
2851 }
2852
2853
computedProjectionRect()2854 QRectF PlotItem::computedProjectionRect() {
2855 QRectF rect;
2856 foreach (PlotRenderItem *renderer, renderItems()) {
2857 if (!renderer->computedProjectionRect().isEmpty()) {
2858 if (rect.isValid()) {
2859 rect = rect.united(renderer->computedProjectionRect());
2860 } else {
2861 rect = renderer->computedProjectionRect();
2862 }
2863 }
2864 }
2865
2866 if (!rect.isValid())
2867 rect = QRectF(QPointF(-0.1, -0.1), QPointF(0.1, 0.1)); //default
2868
2869 return rect;
2870 }
2871
2872
computedRelationalMax(double & minimum,double & maximum)2873 void PlotItem::computedRelationalMax(double &minimum, double &maximum) {
2874 //QRectF rect;
2875 foreach (PlotRenderItem *renderer, renderItems()) {
2876 foreach (RelationPtr relation, renderer->relationList()) {
2877 if (relation->ignoreAutoScale())
2878 continue;
2879
2880 double min, max;
2881 relation->yRange(projectionRect().left(),
2882 projectionRect().right(),
2883 &min, &max);
2884
2885 //If the axis is in log mode, the lower extent will be the
2886 //minimum value larger than zero.
2887 if (yAxis()->axisLog())
2888 minimum = minimum <= 0.0 ? min : qMin(min, minimum);
2889 else
2890 minimum = qMin(min, minimum);
2891
2892 maximum = qMax(max, maximum);
2893 }
2894 }
2895 }
2896
2897
computeBorder(Qt::Orientation orientation,double & minimum,double & maximum) const2898 void PlotItem::computeBorder(Qt::Orientation orientation, double &minimum, double &maximum) const {
2899 //QRectF rect;
2900 foreach (PlotRenderItem *renderer, renderItems()) {
2901 double min = maximum;
2902 double max = minimum;
2903 renderer->computeBorder(orientation, &min, &max);
2904 minimum = qMin(min, minimum);
2905 maximum = qMax(max, maximum);
2906 }
2907 }
2908
2909
resetSelectionRect()2910 void PlotItem::resetSelectionRect() {
2911 foreach (PlotRenderItem *renderer, renderItems()) {
2912 renderer->resetSelectionRect();
2913 }
2914 }
2915
2916
mousePressEvent(QGraphicsSceneMouseEvent * event)2917 void PlotItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
2918 if (event->button() == Qt::LeftButton) {
2919 if (checkBox().contains(event->pos())) {
2920 setTiedZoom(!isTiedZoom(), !isTiedZoom());
2921 ViewItem::mousePressEvent(event);
2922 } else {
2923 ViewItem::mousePressEvent(event);
2924 }
2925 }
2926 }
2927
2928
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)2929 void PlotItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
2930 if (event->button() == Qt::LeftButton && view()->viewMode() == View::Data) {
2931 PlotClickEditRegion region = CONTENT;
2932 if (event->pos().x() - rect().left() < leftLabelMargin()) {
2933 region = LABEL;
2934 } else if (event->pos().y() - rect().top()< topLabelMargin()) {
2935 region = LABEL;
2936 } else if (rect().right()-event->pos().x() < rightLabelMargin()) {
2937 region = LABEL;
2938 } else if (rect().bottom()-event->pos().y() < bottomLabelMargin()) {
2939 region = LABEL;
2940 } else if (rect().bottom()-event->pos().y() < bottomMarginSize()) {
2941 region = XAXIS;
2942 } else if (event->pos().x() - rect().left() < leftMarginSize()) {
2943 region = YAXIS;
2944 }
2945 edit(region);
2946 } else {
2947 ViewItem::mouseDoubleClickEvent(event);
2948 }
2949 }
2950
2951
checkBox() const2952 QPainterPath PlotItem::checkBox() const {
2953 if (!isInSharedAxisBox() || (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared())) {
2954 return ViewItem::checkBox();
2955 } else {
2956 QRectF grip;
2957 if (sharedAxisBox()->isXAxisShared()) {
2958 grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() + sizeOfGrip().width() * .25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * -.25), sizeOfGrip());
2959 } else if (sharedAxisBox()->isYAxisShared()) {
2960 grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() - sizeOfGrip().width() * 1.25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * 1.25), sizeOfGrip());
2961 }
2962 QPainterPath path;
2963 path.addEllipse(grip);
2964 return path;
2965 }
2966 }
2967
2968
tiedZoomCheck() const2969 QPainterPath PlotItem::tiedZoomCheck() const {
2970 if (!isInSharedAxisBox() || (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared())) {
2971 return ViewItem::tiedZoomCheck();
2972 } else {
2973 QRectF grip;
2974 if (sharedAxisBox()->isXAxisShared()) {
2975 grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() + sizeOfGrip().width() * .25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * -.25), sizeOfGrip());
2976 } else if (sharedAxisBox()->isYAxisShared()) {
2977 grip = QRectF(QPointF(_calculatedPlotRect.topRight().x() - sizeOfGrip().width() * 1.25, _calculatedPlotRect.topRight().y() - sizeOfGrip().height() * 1.25), sizeOfGrip());
2978 } else {
2979 qDebug() << "warning: no grip set in PlotItem::tiedZoomCheck (bug?)";
2980 }
2981 QPainterPath path;
2982 if (isXTiedZoom() && isYTiedZoom()) {
2983 path.addEllipse(grip);
2984 } else if (isXTiedZoom()) {
2985 path.moveTo(grip.center());
2986 path.arcTo(grip, 225, 180);
2987 } else if (isYTiedZoom()) {
2988 path.moveTo(grip.center());
2989 path.arcTo(grip, 45, 180);
2990 }
2991 return path;
2992 }
2993 }
2994
2995
supportsTiedZoom() const2996 bool PlotItem::supportsTiedZoom() const {
2997 if (isInSharedAxisBox()) {
2998 if (sharedAxisBox() && sharedAxisBox()->isXAxisShared() && sharedAxisBox()->isYAxisShared() &&
2999 sharedAxisBox()->keyPlot() == this) {
3000 return true;
3001 }
3002 }
3003 return ViewItem::supportsTiedZoom();
3004 }
3005
3006
setAllowUpdates(bool allowed)3007 void PlotItem::setAllowUpdates(bool allowed) {
3008 _allowUpdates = allowed;
3009 UpdateManager::self()->doUpdates(true);
3010 }
3011
3012
plotMaximize()3013 void PlotItem::plotMaximize() {
3014 if (!_plotMaximized && view()->viewMode() != View::Data) {
3015 return;
3016 }
3017
3018 if (_plotMaximized) {
3019 double x_rescale;
3020 double y_rescale;
3021
3022 x_rescale = view()->sceneRect().width()/_plotMaximizedSourceParentRect.width();
3023 y_rescale = view()->sceneRect().height()/_plotMaximizedSourceParentRect.height();
3024 _plotMaximizedSourceRect.setWidth(_plotMaximizedSourceRect.width()*x_rescale);
3025 _plotMaximizedSourceRect.setHeight(_plotMaximizedSourceRect.height()*y_rescale);
3026 _plotMaximizedSourcePosition.setX(_plotMaximizedSourcePosition.x()*x_rescale);
3027 _plotMaximizedSourcePosition.setY(_plotMaximizedSourcePosition.y()*y_rescale);
3028 xAxis()->setAxisVisible(_plotMaximizedBottomVisible);
3029 yAxis()->setAxisVisible(_plotMaximizedLeftVisible);
3030 _leftLabelDetails->setVisible(_plotMaximizedLeftVisible);
3031 _bottomLabelDetails->setVisible(_plotMaximizedBottomVisible);
3032 _rightLabelDetails->setVisible(_plotMaximizedRightVisible);
3033 _topLabelDetails->setVisible(_plotMaximizedTopVisible);
3034 _plotMaximized = false;
3035 PlotItemManager::self()->removeFocusPlot(this);
3036 setParentViewItem(_plotMaximizedSourceParent);
3037 setPos(_plotMaximizedSourcePosition);
3038 setViewRect(_plotMaximizedSourceRect);
3039 setZValue(_plotMaximizedSourceZValue);
3040 view()->setChildMaximized(false);
3041 view()->setFontRescale(1.0);
3042 } else {
3043 _plotMaximizedBottomVisible = _bottomLabelDetails->isVisible();
3044 xAxis()->setAxisVisible(true);
3045 _bottomLabelDetails->setVisible(true);
3046 _plotMaximizedLeftVisible = _leftLabelDetails->isVisible();
3047 yAxis()->setAxisVisible(true);
3048 _leftLabelDetails->setVisible(true);
3049 _plotMaximizedRightVisible = _rightLabelDetails->isVisible();
3050 _rightLabelDetails->setVisible(true);
3051 _plotMaximizedTopVisible = _topLabelDetails->isVisible();
3052 _topLabelDetails->setVisible(true);
3053 _plotMaximized = true;
3054 _plotMaximizedSourcePosition = pos();
3055 _plotMaximizedSourceRect = viewRect();
3056 _plotMaximizedSourceZValue = zValue();
3057 _plotMaximizedSourceParent = parentViewItem();
3058 _plotMaximizedSourceParentRect = view()->sceneRect();
3059
3060 setParentViewItem(0);
3061 setPos(0, 0);
3062 setViewRect(view()->sceneRect());
3063 setZValue(PLOT_MAXIMIZED_ZORDER);
3064 PlotItemManager::self()->setFocusPlot(this);
3065
3066 double rescale = double(view()->sceneRect().width() +
3067 view()->sceneRect().height())/
3068 double(_plotMaximizedSourceRect.width() + _plotMaximizedSourceRect.height());
3069 view()->setChildMaximized(true);
3070 view()->setFontRescale(rescale);
3071 }
3072 if (isInSharedAxisBox()) {
3073 view()->setPlotBordersDirty(true);
3074 }
3075 setPlotBordersDirty();
3076 }
3077
3078
zoomFixedExpression(const QRectF & projection,bool force)3079 void PlotItem::zoomFixedExpression(const QRectF &projection, bool force) {
3080 if (projection.isValid()) {
3081 if (isInSharedAxisBox()) {
3082 ZoomCommand *cmd = new ZoomFixedExpressionCommand(this, projection, force);
3083 _undoStack->push(cmd);
3084 // cmd->redo();
3085 if (!force) {
3086 sharedAxisBox()->zoomFixedExpression(projection, this);
3087 } else {
3088 yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3089 xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3090 setProjectionRect(QRectF(projection.x(), projection.y(), projection.width(), projection.height()));
3091 }
3092 } else {
3093 ZoomCommand *cmd = new ZoomFixedExpressionCommand(this, projection, force);
3094 _undoStack->push(cmd);
3095 // cmd->redo();
3096 }
3097 }
3098 }
3099
3100
zoomXRange(const QRectF & projection,bool force)3101 void PlotItem::zoomXRange(const QRectF &projection, bool force) {
3102 if (projection.isValid()) {
3103 if (isInSharedAxisBox()) {
3104 if (!force) {
3105 sharedAxisBox()->zoomXRange(projection, this);
3106 } else {
3107 xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3108 setProjectionRect(QRectF(projection.x(), projectionRect().y(), projection.width(), projectionRect().height()));
3109 }
3110 } else {
3111 ZoomCommand *cmd = new ZoomXRangeCommand(this, projection, force);
3112 _undoStack->push(cmd);
3113 // cmd->redo();
3114 }
3115 }
3116 }
3117
3118
zoomYRange(const QRectF & projection,bool force)3119 void PlotItem::zoomYRange(const QRectF &projection, bool force) {
3120 if (projection.isValid()) {
3121 if (isInSharedAxisBox()) {
3122 if (!force) {
3123 sharedAxisBox()->zoomYRange(projection, this);
3124 } else {
3125 yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
3126 setProjectionRect(QRectF(projectionRect().x(), projection.y(), projectionRect().width(), projection.height()));
3127 }
3128 } else {
3129 ZoomCommand *cmd = new ZoomYRangeCommand(this, projection, force);
3130 _undoStack->push(cmd);
3131 // cmd->redo();
3132 }
3133 }
3134 }
3135
3136
zoomMaximum(bool force)3137 void PlotItem::zoomMaximum(bool force) {
3138 if (isInSharedAxisBox() && (!force)) {
3139 sharedAxisBox()->zoomMaximum(this);
3140 } else {
3141 ZoomCommand *cmd = new ZoomMaximumCommand(this, force);
3142 _undoStack->push(cmd);
3143 //cmd->redo();
3144 }
3145 }
3146
adjustImageColorScale()3147 void PlotItem::adjustImageColorScale() {
3148 const double per[] = {0.0, 0.0001, 0.001, 0.005, 0.02, 0.1};
3149 const int length = sizeof(per) / sizeof(double);
3150
3151 if (++_i_per >= length) {
3152 _i_per = 0;
3153 }
3154 foreach (PlotRenderItem *renderer, renderItems()) {
3155 foreach (RelationPtr relation, renderer->relationList()) {
3156 if (ImagePtr image = kst_cast<Image>(relation)) {
3157 image->writeLock();
3158 image->setThresholdToSpikeInsensitive(per[_i_per]);
3159 image->registerChange();
3160 image->unlock();
3161 }
3162 }
3163 }
3164 UpdateManager::self()->doUpdates(true);
3165 }
3166
zoomMaxSpikeInsensitive(bool force)3167 void PlotItem::zoomMaxSpikeInsensitive(bool force) {
3168 if (isInSharedAxisBox() && !force) {
3169 sharedAxisBox()->zoomMaxSpikeInsensitive(this);
3170 } else {
3171 ZoomCommand *cmd = new ZoomMaxSpikeInsensitiveCommand(this, force);
3172 _undoStack->push(cmd);
3173 //cmd->redo();
3174 }
3175 }
3176
3177
zoomPrevious()3178 void PlotItem::zoomPrevious() {
3179 if (!isInSharedAxisBox()) {
3180 if (_undoStack->canUndo()) {
3181 QAction *undoAction = _undoStack->createUndoAction(this);
3182 if (undoAction) {
3183 undoAction->activate(QAction::Trigger);
3184 }
3185 }
3186 }
3187 }
3188
3189
zoomTied()3190 void PlotItem::zoomTied() {
3191 setTiedZoom(!isTiedZoom(), !isTiedZoom());
3192 }
3193
3194
zoomXTied()3195 void PlotItem::zoomXTied() {
3196 setTiedZoom(!isXTiedZoom(), isYTiedZoom());
3197 }
3198
3199
zoomYTied()3200 void PlotItem::zoomYTied() {
3201 setTiedZoom(isXTiedZoom(), !isYTiedZoom());
3202 }
3203
3204
zoomMeanCentered(bool force)3205 void PlotItem::zoomMeanCentered(bool force) {
3206 if (isInSharedAxisBox() && !force) {
3207 sharedAxisBox()->zoomMeanCentered(this);
3208 } else {
3209 ZoomCommand *cmd = new ZoomMeanCenteredCommand(this, force);
3210 _undoStack->push(cmd);
3211 // cmd->redo();
3212 }
3213 }
3214
3215
zoomYMeanCentered(qreal dY,bool force)3216 void PlotItem::zoomYMeanCentered(qreal dY, bool force) {
3217 if (isInSharedAxisBox() && !force) {
3218 sharedAxisBox()->zoomYMeanCentered(dY, this);
3219 } else {
3220 ZoomCommand *cmd = new ZoomYMeanCenteredCommand(this, dY, force);
3221 _undoStack->push(cmd);
3222 // cmd->redo();
3223 }
3224 }
3225
3226
zoomXMeanCentered(qreal dX,bool force)3227 void PlotItem::zoomXMeanCentered(qreal dX, bool force) {
3228 if (isInSharedAxisBox() && !force) {
3229 sharedAxisBox()->zoomXMeanCentered(this);
3230 } else {
3231 ZoomCommand *cmd = new ZoomXMeanCenteredCommand(this, dX, force);
3232 _undoStack->push(cmd);
3233 // cmd->redo();
3234 }
3235 }
3236
3237
zoomXMaximum(bool force)3238 void PlotItem::zoomXMaximum(bool force) {
3239 if (isInSharedAxisBox() && !force) {
3240 sharedAxisBox()->zoomXMaximum(this);
3241 } else {
3242 ZoomCommand *cmd = new ZoomXMaximumCommand(this, force);
3243 _undoStack->push(cmd);
3244 // cmd->redo();
3245 }
3246 }
3247
3248
zoomXNoSpike(bool force)3249 void PlotItem::zoomXNoSpike(bool force) {
3250 if (isInSharedAxisBox() && !force) {
3251 sharedAxisBox()->zoomXNoSpike(this);
3252 } else {
3253 ZoomCommand *cmd = new ZoomXNoSpikeCommand(this, force);
3254 _undoStack->push(cmd);
3255 // cmd->redo();
3256 }
3257 }
3258
3259
zoomXAutoBorder(bool force)3260 void PlotItem::zoomXAutoBorder(bool force) {
3261 if (isInSharedAxisBox() && !force) {
3262 sharedAxisBox()->zoomXAutoBorder(this);
3263 } else {
3264 ZoomCommand *cmd = new ZoomXAutoBorderCommand(this, force);
3265 _undoStack->push(cmd);
3266 // cmd->redo();
3267 }
3268 }
3269
3270
zoomXRight(bool force,bool scroll_far)3271 void PlotItem::zoomXRight(bool force, bool scroll_far) {
3272 if (isInSharedAxisBox() && !force) {
3273 sharedAxisBox()->zoomXRight(this, scroll_far);
3274 } else {
3275 ZoomCommand *cmd;
3276 if (scroll_far) {
3277 cmd = new ZoomXFarRightCommand(this, force);
3278 } else {
3279 cmd = new ZoomXRightCommand(this, force);
3280 }
3281 _undoStack->push(cmd);
3282 //cmd->redo();
3283 }
3284 }
3285
3286
zoomXLeft(bool force,bool scroll_far)3287 void PlotItem::zoomXLeft(bool force, bool scroll_far) {
3288 if (isInSharedAxisBox() && !force) {
3289 sharedAxisBox()->zoomXLeft(this, scroll_far);
3290 } else {
3291 ZoomCommand *cmd;
3292 if (scroll_far) {
3293 cmd = new ZoomXFarLeftCommand(this, force);
3294 } else {
3295 cmd = new ZoomXLeftCommand(this, force);
3296 }
3297 _undoStack->push(cmd);
3298 //cmd->redo();
3299 }
3300 }
3301
3302
zoomXFarRight(bool force)3303 void PlotItem::zoomXFarRight(bool force) {
3304 zoomXRight(force, true);
3305 }
3306
zoomXFarLeft(bool force)3307 void PlotItem::zoomXFarLeft(bool force) {
3308 zoomXLeft(force, true);
3309 }
3310
zoomXOut(bool force)3311 void PlotItem::zoomXOut(bool force) {
3312 resetSelectionRect();
3313 if (isInSharedAxisBox() && !force) {
3314 sharedAxisBox()->zoomXOut(this);
3315 } else {
3316 ZoomCommand *cmd = new ZoomXOutCommand(this, force);
3317 _undoStack->push(cmd);
3318 // cmd->redo();
3319 }
3320 }
3321
3322
zoomXIn(bool force)3323 void PlotItem::zoomXIn(bool force) {
3324 resetSelectionRect();
3325 if (isInSharedAxisBox() && !force) {
3326 sharedAxisBox()->zoomXIn(this);
3327 } else {
3328 ZoomCommand *cmd = new ZoomXInCommand(this, force);
3329 _undoStack->push(cmd);
3330 // cmd->redo();
3331 }
3332 }
3333
3334
zoomNormalizeXtoY(bool force)3335 void PlotItem::zoomNormalizeXtoY(bool force) {
3336 if (xAxis()->axisLog() || yAxis()->axisLog())
3337 return; //FIXME: if both are log, this could be supported
3338
3339 if (isInSharedAxisBox() && !force) {
3340 sharedAxisBox()->zoomNormalizeXtoY(this);
3341 } else {
3342 ZoomCommand *cmd = new ZoomNormalizeXToYCommand(this, force);
3343 _undoStack->push(cmd);
3344 // cmd->redo();
3345 }
3346 }
3347
3348
zoomLogX(bool force,bool autoLog,bool enableLog)3349 void PlotItem::zoomLogX(bool force, bool autoLog, bool enableLog) {
3350 if (isInSharedAxisBox() && !force) {
3351 sharedAxisBox()->zoomLogX(this);
3352 } else {
3353 bool log = enableLog;
3354 if (autoLog) {
3355 log = !xAxis()->axisLog();
3356 }
3357 ZoomCommand *cmd = new ZoomXLogCommand(this, log, force);
3358 _undoStack->push(cmd);
3359 // cmd->redo();
3360 }
3361 }
3362
3363
zoomYLocalMaximum(bool force)3364 void PlotItem::zoomYLocalMaximum(bool force) {
3365 if (isInSharedAxisBox() && !force) {
3366 sharedAxisBox()->zoomYLocalMaximum(this);
3367 } else {
3368 ZoomCommand *cmd = new ZoomYLocalMaximumCommand(this, force);
3369 _undoStack->push(cmd);
3370 // cmd->redo();
3371 }
3372 }
3373
3374
zoomYMaximum(bool force)3375 void PlotItem::zoomYMaximum(bool force) {
3376 if (isInSharedAxisBox() && !force) {
3377 sharedAxisBox()->zoomYMaximum(this);
3378 } else {
3379 ZoomCommand *cmd = new ZoomYMaximumCommand(this, force);
3380 _undoStack->push(cmd);
3381 // cmd->redo();
3382 }
3383 }
3384
3385
zoomYNoSpike(bool force)3386 void PlotItem::zoomYNoSpike(bool force) {
3387 if (isInSharedAxisBox() && !force) {
3388 sharedAxisBox()->zoomYNoSpike(this);
3389 } else {
3390 ZoomCommand *cmd = new ZoomYNoSpikeCommand(this, force);
3391 _undoStack->push(cmd);
3392 // cmd->redo();
3393 }
3394 }
3395
3396
zoomYAutoBorder(bool force)3397 void PlotItem::zoomYAutoBorder(bool force) {
3398 if (isInSharedAxisBox() && !force) {
3399 sharedAxisBox()->zoomYAutoBorder(this);
3400 } else {
3401 ZoomCommand *cmd = new ZoomYAutoBorderCommand(this, force);
3402 _undoStack->push(cmd);
3403 // cmd->redo();
3404 }
3405 }
3406
3407
zoomYUp(bool force)3408 void PlotItem::zoomYUp(bool force) {
3409 if (isInSharedAxisBox() && !force) {
3410 sharedAxisBox()->zoomYUp(this);
3411 } else {
3412 ZoomCommand *cmd = new ZoomYUpCommand(this, force);
3413 _undoStack->push(cmd);
3414 // cmd->redo();
3415 }
3416 }
3417
3418
zoomYDown(bool force)3419 void PlotItem::zoomYDown(bool force) {
3420 if (isInSharedAxisBox() && !force) {
3421 sharedAxisBox()->zoomYDown(this);
3422 } else {
3423 ZoomCommand *cmd = new ZoomYDownCommand(this, force);
3424 _undoStack->push(cmd);
3425 //cmd->redo();
3426 }
3427 }
3428
3429
zoomYOut(bool force)3430 void PlotItem::zoomYOut(bool force) {
3431 resetSelectionRect();
3432 if (isInSharedAxisBox() && !force) {
3433 sharedAxisBox()->zoomYOut(this);
3434 } else {
3435 ZoomCommand *cmd = new ZoomYOutCommand(this, force);
3436 _undoStack->push(cmd);
3437 // cmd->redo();
3438 }
3439 }
3440
3441
zoomYIn(bool force)3442 void PlotItem::zoomYIn(bool force) {
3443 resetSelectionRect();
3444 if (isInSharedAxisBox() && !force) {
3445 sharedAxisBox()->zoomYIn(this);
3446 } else {
3447 ZoomCommand *cmd = new ZoomYInCommand(this, force);
3448 _undoStack->push(cmd);
3449 // cmd->redo();
3450 }
3451 }
3452
3453
zoomNormalizeYtoX(bool force)3454 void PlotItem::zoomNormalizeYtoX(bool force) {
3455 if (xAxis()->axisLog() || yAxis()->axisLog())
3456 return; //apparently we don't want to do anything here according to kst2dplot...
3457
3458 if (isInSharedAxisBox() && !force) {
3459 sharedAxisBox()->zoomNormalizeYtoX(this);
3460 } else {
3461 ZoomCommand *cmd = new ZoomNormalizeYToXCommand(this, force);
3462 _undoStack->push(cmd);
3463 // cmd->redo();
3464 }
3465 }
3466
3467
zoomLogY(bool force,bool autoLog,bool enableLog)3468 void PlotItem::zoomLogY(bool force, bool autoLog, bool enableLog) {
3469 if (isInSharedAxisBox() && !force) {
3470 sharedAxisBox()->zoomLogY(this);
3471 } else {
3472 bool log = enableLog;
3473 if (autoLog) {
3474 log = !yAxis()->axisLog();
3475 }
3476 ZoomCommand *cmd = new ZoomYLogCommand(this, log, force);
3477 _undoStack->push(cmd);
3478 // cmd->redo();
3479 }
3480 }
3481
zoomOut(bool force)3482 void PlotItem::zoomOut(bool force) {
3483 zoomYOut(force);
3484 zoomXOut(force);
3485 }
3486
zoomIn(bool force)3487 void PlotItem::zoomIn(bool force) {
3488 zoomYIn(force);
3489 zoomXIn(force);
3490 }
3491
copyStatus()3492 void PlotItem::copyStatus() {
3493 kstApp->clipboard()->setText(kstApp->mainWindow()->statusMessage());
3494 kstApp->mainWindow()->setStatusMessage(tr("Info copied to clipboard: ") + kstApp->mainWindow()->statusMessage());
3495 }
3496
copyXCoord()3497 void PlotItem::copyXCoord() {
3498 QString valueString = QString::number(renderItem()->statusMessagePoint.x(), 'g', 12);
3499 kstApp->clipboard()->setText(valueString);
3500 kstApp->mainWindow()->setStatusMessage(tr("X coordinate copied to clipboard: ") + valueString);
3501 }
3502
copyYCoord()3503 void PlotItem::copyYCoord() {
3504 QString valueString = QString::number(renderItem()->statusMessagePoint.y(), 'g', 12);
3505 kstApp->clipboard()->setText(valueString);
3506 kstApp->mainWindow()->setStatusMessage(tr("Y coordinate copied to clipboard: ") + valueString);
3507 }
3508
descriptionTip() const3509 QString PlotItem::descriptionTip() const {
3510 QString contents;
3511 foreach (PlotRenderItem *renderer, renderItems()) {
3512 foreach (RelationPtr relation, renderer->relationList()) {
3513 contents += QString(" %1\n").arg(relation->Name());
3514 }
3515 }
3516
3517 return tr("Plot: %1 \nContents:\n %2").arg(Name()).arg(contents);
3518 }
3519
3520
_automaticDescriptiveName() const3521 QString PlotItem::_automaticDescriptiveName() const {
3522 QString name = tr("Empty Plot");
3523 int n=0;
3524 foreach (PlotRenderItem *renderer, renderItems()) {
3525 foreach (RelationPtr relation, renderer->relationList()) {
3526 if (n==0) {
3527 name = relation->descriptiveName();
3528 }
3529 n++;
3530 }
3531 }
3532 if (n>1) {
3533 name += ", ...";
3534 }
3535 return name;
3536 }
3537
3538
currentZoomState()3539 ZoomState PlotItem::currentZoomState() {
3540 ZoomState zoomState;
3541 zoomState.item = this; //the origin of this ZoomState
3542 zoomState.projectionRect = projectionRect();
3543 zoomState.xAxisZoomMode = xAxis()->axisZoomMode();
3544 zoomState.yAxisZoomMode = yAxis()->axisZoomMode();
3545 zoomState.isXAxisLog = xAxis()->axisLog();
3546 zoomState.isYAxisLog = yAxis()->axisLog();
3547 return zoomState;
3548 }
3549
3550
setCurrentZoomState(ZoomState zoomState)3551 void PlotItem::setCurrentZoomState(ZoomState zoomState) {
3552 _xAxis->setAxisZoomMode(PlotAxis::ZoomMode(zoomState.xAxisZoomMode));
3553 _yAxis->setAxisZoomMode(PlotAxis::ZoomMode(zoomState.yAxisZoomMode));
3554 _xAxis->setAxisLog(zoomState.isXAxisLog);
3555 _yAxis->setAxisLog(zoomState.isYAxisLog);
3556 setProjectionRect(zoomState.projectionRect);
3557 }
3558
3559
updateChildGeometry(const QRectF & oldParentRect,const QRectF & newParentRect)3560 void PlotItem::updateChildGeometry(const QRectF &oldParentRect, const QRectF &newParentRect) {
3561 ViewItem::updateChildGeometry(oldParentRect, newParentRect);
3562 setPlotBordersDirty(true);
3563 setLabelsDirty();
3564 setAxisLabelsDirty();
3565 setPlotPixmapDirty();
3566 }
3567
saveAsDialogDefaults() const3568 void PlotItem::saveAsDialogDefaults() const {
3569 dialogDefaults().setValue(defaultsGroupName()+"/globalFontFamily", QVariant(globalFont()).toString());
3570 dialogDefaults().setValue(defaultsGroupName()+"/globalFontScale",globalFontScale());
3571 dialogDefaults().setValue(defaultsGroupName()+"/globalFontColor", QVariant(globalFontColor()).toString());
3572
3573 leftLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/leftFont"));
3574 rightLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/rightFont"));
3575 topLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/topFont"));
3576 bottomLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/bottomFont"));
3577 numberLabelDetails()->saveAsDialogDefaults(QString(defaultsGroupName()+"/numberFont"));
3578
3579 _xAxis->saveAsDialogDefaults(defaultsGroupName()+"/xAxis");
3580 _yAxis->saveAsDialogDefaults(defaultsGroupName()+"/yAxis");
3581 }
3582
saveDialogDefaultsFont(QFont F,QColor C)3583 void PlotItem::saveDialogDefaultsFont(QFont F, QColor C) {
3584 dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontFamily", QVariant(F).toString());
3585 dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontScale",F.pointSize());
3586 dialogDefaults().setValue(staticDefaultsGroupName()+"/globalFontColor", QVariant(C).toString());
3587
3588 PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/leftFont", F, C, true);
3589 PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/rightFont", F, C, true);
3590 PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/topFont", F, C, true);
3591 PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/bottomFont", F, C, true);
3592 PlotLabel::saveDialogDefaults(staticDefaultsGroupName()+"/numberFont", F, C, true);
3593 }
3594
setFont(const QFont & f,const QColor & c)3595 void PlotItem::setFont(const QFont &f, const QColor &c) {
3596 leftLabelDetails()->setFontUseGlobal(true);
3597 rightLabelDetails()->setFontUseGlobal(true);
3598 topLabelDetails()->setFontUseGlobal(true);
3599 bottomLabelDetails()->setFontUseGlobal(true);
3600 numberLabelDetails()->setFontUseGlobal(true);
3601 setGlobalFontColor(c);
3602 setGlobalFont(f);
3603 setGlobalFontScale(f.pointSize());
3604 leftLabelDetails()->setFontColor(c);
3605 rightLabelDetails()->setFontColor(c);
3606 topLabelDetails()->setFontColor(c);
3607 bottomLabelDetails()->setFontColor(c);
3608 numberLabelDetails()->setFontColor(c);
3609 }
3610
3611
PlotLabel(PlotItem * plotItem)3612 PlotLabel::PlotLabel(PlotItem *plotItem) : QObject(),
3613 _plotItem(plotItem),
3614 _visible(true),
3615 _fontScale(12),
3616 _fontUseGlobal(true),
3617 _isAuto(true) {
3618
3619 }
3620
3621
setDetails(const QString & label,bool is_auto,const bool use_global,const QFont & font,const qreal scale,const QColor & color)3622 void PlotLabel::setDetails(const QString &label, bool is_auto,
3623 const bool use_global, const QFont &font,
3624 const qreal scale, const QColor &color) {
3625 if ((label != _text) || (_isAuto != is_auto) ||
3626 (use_global != _fontUseGlobal) ||
3627 (font != _font) ||
3628 (scale != _fontScale) ||
3629 (color != _fontColor)) {
3630 _text = label;
3631 _isAuto = is_auto;
3632 _fontUseGlobal = use_global;
3633 _font = font;
3634 _fontScale = scale;
3635 _fontColor = color;
3636 emit labelChanged();
3637 }
3638 }
3639
3640
calculatedFont(const QPaintDevice & p)3641 QFont PlotLabel::calculatedFont(const QPaintDevice &p) {
3642 QFont tempFont;
3643 if (fontUseGlobal()) {
3644 tempFont = _plotItem->globalFont();
3645 tempFont.setPointSizeF(_plotItem->view()->scaledFontSize(_plotItem->globalFontScale(),p));
3646 } else {
3647 tempFont = font();
3648 tempFont.setPointSizeF(_plotItem->view()->scaledFontSize(fontScale(),p));
3649 }
3650 return tempFont;
3651 }
3652
3653
isVisible() const3654 bool PlotLabel::isVisible() const {
3655 return _visible;
3656 }
3657
3658
setVisible(bool visible)3659 void PlotLabel::setVisible(bool visible) {
3660 if (_visible == visible)
3661 return;
3662
3663 _visible = visible;
3664 emit labelChanged();
3665 }
3666
3667
fontUseGlobal() const3668 bool PlotLabel::fontUseGlobal() const {
3669 return _fontUseGlobal;
3670 }
3671
3672
setFontUseGlobal(const bool use_global)3673 void PlotLabel::setFontUseGlobal(const bool use_global) {
3674 if (_fontUseGlobal == use_global)
3675 return;
3676
3677 _fontUseGlobal = use_global;
3678 emit labelChanged();
3679 }
3680
3681
text() const3682 QString PlotLabel::text() const {
3683 return _text;
3684 }
3685
3686
setText(const QString & label)3687 void PlotLabel::setText(const QString &label) {
3688 if (label == _text) {
3689 return;
3690 }
3691 _text = label;
3692 emit labelChanged();
3693 }
3694
fontScale() const3695 qreal PlotLabel::fontScale() const {
3696 return _fontScale;
3697 }
3698
3699
setFontScale(const qreal scale)3700 void PlotLabel::setFontScale(const qreal scale) {
3701 if (scale != _fontScale) {
3702 _fontScale = scale;
3703 emit labelChanged();
3704 }
3705 }
3706
3707
font() const3708 QFont PlotLabel::font() const {
3709 return _font;
3710 }
3711
3712
setFont(const QFont & font)3713 void PlotLabel::setFont(const QFont &font) {
3714 if (font != _font) {
3715 _font = font;
3716 emit labelChanged();
3717 }
3718 }
3719
3720
fontColor() const3721 QColor PlotLabel::fontColor() const {
3722 return _fontColor;
3723 }
3724
3725
setFontColor(const QColor & color)3726 void PlotLabel::setFontColor(const QColor &color) {
3727 if (color != _fontColor) {
3728 _fontColor = color;
3729 emit labelChanged();
3730 }
3731 }
3732
3733
saveInPlot(QXmlStreamWriter & xml,QString labelId)3734 void PlotLabel::saveInPlot(QXmlStreamWriter &xml, QString labelId) {
3735 xml.writeStartElement("plotlabel");
3736 xml.writeAttribute("id", labelId);
3737 xml.writeAttribute("visible", QVariant(_visible).toString());
3738 xml.writeAttribute("overridetext", _text);
3739 xml.writeAttribute("autolabel", QVariant(_isAuto).toString());
3740 xml.writeAttribute("font", QVariant(_font).toString());
3741 xml.writeAttribute("fontscale", QVariant(_fontScale).toString());
3742 xml.writeAttribute("fontcolor", QVariant(_fontColor).toString());
3743 xml.writeAttribute("fontuseglobal", QVariant(_fontUseGlobal).toString());
3744 xml.writeEndElement();
3745 }
3746
3747
configureFromXml(QXmlStreamReader & xml,ObjectStore * store)3748 bool PlotLabel::configureFromXml(QXmlStreamReader &xml, ObjectStore *store) {
3749 Q_UNUSED(store);
3750 bool validTag = true;
3751
3752 QString primaryTag = xml.name().toString();
3753 QXmlStreamAttributes attrs = xml.attributes();
3754 QStringRef av = attrs.value("visible");
3755 if (!av.isNull()) {
3756 setVisible(QVariant(av.toString()).toBool());
3757 }
3758 av = attrs.value("overridetext");
3759 if (!av.isNull()) {
3760 setText(av.toString());
3761 }
3762 av = attrs.value("autolabel");
3763 if (!av.isNull()) {
3764 setIsAuto(QVariant(av.toString()).toBool());
3765 }
3766 av = attrs.value("fontuseglobal");
3767 if (!av.isNull()) {
3768 setFontUseGlobal(QVariant(av.toString()).toBool());
3769 }
3770 av = attrs.value("font");
3771 if (!av.isNull()) {
3772 QFont font;
3773 font.fromString(av.toString());
3774 setFont(font);
3775 }
3776 av = attrs.value("fontcolor");
3777 if (!av.isNull()) {
3778 setFontColor(QColor(av.toString()));
3779 }
3780 av = attrs.value("fontscale");
3781 if (!av.isNull()) {
3782 setFontScale(QVariant(av.toString()).toDouble());
3783 }
3784
3785 QString expectedEnd;
3786 while (!(xml.isEndElement() && (xml.name().toString() == primaryTag))) {
3787 if (xml.isEndElement()) {
3788 if (xml.name().toString() != expectedEnd) {
3789 validTag = false;
3790 break;
3791 }
3792 }
3793 xml.readNext();
3794 }
3795
3796 return validTag;
3797 }
3798
saveAsDialogDefaults(const QString & group) const3799 void PlotLabel::saveAsDialogDefaults(const QString &group) const {
3800 QFont F = font();
3801 F.setPointSize(fontScale());
3802 PlotLabel::saveDialogDefaults(group, F, fontColor(), fontUseGlobal());
3803 }
3804
saveDialogDefaults(const QString & group,const QFont & F,const QColor & C,bool U)3805 void PlotLabel::saveDialogDefaults(const QString &group, const QFont &F, const QColor &C, bool U) {
3806 dialogDefaults().setValue(group+QString("Global"), U);
3807 dialogDefaults().setValue(group+QString("Family"), QVariant(F).toString());
3808 dialogDefaults().setValue(group+QString("Scale"), F.pointSize());
3809 dialogDefaults().setValue(group+QString("Color"), QVariant(C).toString());
3810 }
3811
createItem()3812 void CreatePlotCommand::createItem() {
3813 _item = new PlotItem(_view);
3814 _view->setCursor(Qt::CrossCursor);
3815
3816 CreateCommand::createItem();
3817 }
3818
3819
createItem()3820 void CreatePlotForCurve::createItem() {
3821 _item = new PlotItem(_view);
3822 creationComplete(); //add to undo stack
3823 }
3824
3825
PlotItemFactory()3826 PlotItemFactory::PlotItemFactory()
3827 : GraphicsFactory() {
3828 registerFactory("plot", this);
3829 }
3830
3831
~PlotItemFactory()3832 PlotItemFactory::~PlotItemFactory() {
3833 }
3834
generateGraphics(QXmlStreamReader & xml,ObjectStore * store,View * view,ViewItem * parent)3835 ViewItem* PlotItemFactory::generateGraphics(QXmlStreamReader& xml, ObjectStore *store, View *view, ViewItem *parent) {
3836 PlotItem *rc = 0;
3837 double x = 0, y = 0, w = 10, h = 10;
3838 bool xTiedZoom = false, yTiedZoom = false;
3839 while (!xml.atEnd()) {
3840 bool validTag = true;
3841 if (xml.isStartElement()) {
3842 if (!rc && xml.name().toString() == "plot") {
3843 Q_ASSERT(!rc);
3844
3845 QXmlStreamAttributes attrs = xml.attributes();
3846 QStringRef av;
3847
3848 Object::processShortNameIndexAttributes(attrs);
3849
3850 rc = new PlotItem(view);
3851 if (parent) {
3852 rc->setParentViewItem(parent);
3853 }
3854
3855 av = attrs.value("tiedxzoom");
3856 if (!av.isNull()) {
3857 xTiedZoom = QVariant(av.toString()).toBool();
3858 }
3859 av = attrs.value("tiedyzoom");
3860 if (!av.isNull()) {
3861 yTiedZoom = QVariant(av.toString()).toBool();
3862 }
3863 av = attrs.value("leftlabelvisible");
3864 if (!av.isNull()) {
3865 rc->leftLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3866 }
3867 av = attrs.value("bottomlabelvisible");
3868 if (!av.isNull()) {
3869 rc->bottomLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3870 }
3871 av = attrs.value("rightlabelvisible");
3872 if (!av.isNull()) {
3873 rc->rightLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3874 }
3875 av = attrs.value("toplabelvisible");
3876 if (!av.isNull()) {
3877 rc->topLabelDetails()->setVisible(QVariant(av.toString()).toBool());
3878 }
3879 av = attrs.value("globalfont");
3880 if (!av.isNull()) {
3881 QFont font;
3882 font.fromString(av.toString());
3883 rc->setGlobalFont(font);
3884 }
3885 double fontscale = 0.0;
3886 av = attrs.value("globalfontscale");
3887 if (!av.isNull()) {
3888 fontscale = QVariant(av.toString()).toDouble();
3889 }
3890 if (fontscale < 0.1) {
3891 fontscale = 14.0;
3892 }
3893 rc->setGlobalFontScale(fontscale);
3894 av = attrs.value("globalfontcolor");
3895 if (!av.isNull()) {
3896 rc->setGlobalFontColor(QColor(av.toString()));
3897 }
3898 av = attrs.value("showlegend");
3899 if (!av.isNull()) {
3900 rc->setShowLegend(QVariant(av.toString()).toBool());
3901 }
3902
3903 av = attrs.value("hidebottomaxislabel");
3904 if (!av.isNull()) {
3905 rc->setManuallyHideBottomAxisLabel(QVariant(av.toString()).toBool());
3906 }
3907
3908 av = attrs.value("hidetopaxislabel");
3909 if (!av.isNull()) {
3910 rc->setManuallyHideTopAxisLabel(QVariant(av.toString()).toBool());
3911 }
3912
3913 av = attrs.value("hideleftaxislabel");
3914 if (!av.isNull()) {
3915 rc->setManuallyHideLeftAxisLabel(QVariant(av.toString()).toBool());
3916 }
3917
3918 av = attrs.value("hiderightaxislabel");
3919 if (!av.isNull()) {
3920 rc->setManuallyHideRightAxisLabel(QVariant(av.toString()).toBool());
3921 }
3922
3923 av = attrs.value("numberaxislabelscale");
3924 if (!av.isNull()) {
3925 rc->setUseAxisScale(QVariant(av.toString()).toBool());
3926 }
3927
3928 if (attrs.value("descriptiveNameIsManual").toString() == "true") {
3929 rc->setDescriptiveName(attrs.value("descriptiveName").toString());
3930 }
3931
3932 // Add any new specialized PlotItem Properties here.
3933 } else if (xml.name().toString() == "projectionrect") {
3934 QXmlStreamAttributes attrs = xml.attributes();
3935 QStringRef av;
3936 av = attrs.value("width");
3937 if (!av.isNull()) {
3938 w = av.toString().toDouble();
3939 }
3940 av = attrs.value("height");
3941 if (!av.isNull()) {
3942 h = av.toString().toDouble();
3943 }
3944 av = attrs.value("x");
3945 if (!av.isNull()) {
3946 x = av.toString().toDouble();
3947 }
3948 av = attrs.value("y");
3949 if (!av.isNull()) {
3950 y = av.toString().toDouble();
3951 }
3952 xml.readNext();
3953 } else if (xml.name().toString() == "plotaxis") {
3954 Q_ASSERT(rc);
3955 QXmlStreamAttributes subattrs = xml.attributes();
3956 QStringRef av = subattrs.value("id");
3957 if (!av.isNull()) {
3958 if (av == "xaxis") {
3959 rc->xAxis()->configureFromXml(xml, store);
3960 } else if (av == "yaxis") {
3961 rc->yAxis()->configureFromXml(xml, store);
3962 }
3963 }
3964 xml.readNext();
3965 } else if (xml.name().toString() == "plotlabel") {
3966 Q_ASSERT(rc);
3967 QXmlStreamAttributes subattrs = xml.attributes();
3968 QStringRef av = subattrs.value("id");
3969 if (!av.isNull()) {
3970 if (av == "leftlabel") {
3971 rc->leftLabelDetails()->configureFromXml(xml, store);
3972 } else if (av == "rightlabel") {
3973 rc->rightLabelDetails()->configureFromXml(xml, store);
3974 } else if (av == "toplabel") {
3975 rc->topLabelDetails()->configureFromXml(xml, store);
3976 } else if (av == "bottomlabel") {
3977 rc->bottomLabelDetails()->configureFromXml(xml, store);
3978 } else if (av == "numberlabel") {
3979 rc->numberLabelDetails()->configureFromXml(xml, store); }
3980 }
3981 xml.readNext();
3982 } else if (xml.name().toString() == "cartesianrender") {
3983 Q_ASSERT(rc);
3984 PlotRenderItem * renderItem = rc->renderItem(PlotRenderItem::Cartesian);
3985 if (renderItem) {
3986 validTag = renderItem->configureFromXml(xml, store);
3987 }
3988 } else if (xml.name().toString() == "legend") {
3989 Q_ASSERT(rc);
3990 validTag = rc->legend()->configureFromXml(xml, store);
3991 } else {
3992 Q_ASSERT(rc);
3993 if (!rc->parse(xml, validTag) && validTag) {
3994 ViewItem *i = GraphicsFactory::parse(xml, store, view, rc);
3995 if (!i) {
3996 }
3997 }
3998 }
3999 } else if (xml.isEndElement()) {
4000 if (xml.name().toString() == "plot") {
4001 break;
4002 } else {
4003 validTag = false;
4004 }
4005 }
4006 if (!validTag) {
4007 Debug::self()->log(QObject::tr("Error creating plot object from Kst file."), Debug::Warning);
4008 delete rc;
4009 return 0;
4010 }
4011 xml.readNext();
4012 }
4013 rc->setProjectionRect(QRectF(QPointF(x, y), QSizeF(w, h)));
4014 rc->setTiedZoom(xTiedZoom, yTiedZoom);
4015 return rc;
4016 }
4017
4018
ZoomCommand(PlotItem * item,const QString & text,bool forced)4019 ZoomCommand::ZoomCommand(PlotItem *item, const QString &text, bool forced)
4020 : ViewItemCommand(item, text, false), _plotItem(item) {
4021
4022 if (!item->isTiedZoom() || forced) {
4023 _originalStates << item->currentZoomState();
4024 } else {
4025 _viewItems = PlotItemManager::tiedZoomViewItems(item);
4026
4027 QList<PlotItem*> plots = PlotItemManager::tiedZoomPlots(item);
4028 foreach (PlotItem *plotItem, plots) {
4029 if (plotItem->isInSharedAxisBox()) {
4030 if (!_viewItems.contains(plotItem->sharedAxisBox())) {
4031 _viewItems << plotItem->sharedAxisBox();
4032 }
4033 } else { // plots already in a shared box are going to get zoomed anyway, so don't re-add them.
4034 _originalStates << plotItem->currentZoomState();
4035 }
4036 }
4037 }
4038 }
4039
4040
~ZoomCommand()4041 ZoomCommand::~ZoomCommand() {
4042 }
4043
4044
undo()4045 void ZoomCommand::undo() {
4046 foreach (const ZoomState &state, _originalStates) {
4047 state.item->setCurrentZoomState(state);
4048 }
4049 kstApp->mainWindow()->document()->setChanged(true);
4050 }
4051
4052
redo()4053 void ZoomCommand::redo() {
4054 bool tiedX = _plotItem->isXTiedZoom();
4055 bool tiedY = _plotItem->isYTiedZoom();
4056
4057 foreach (const ZoomState &state, _originalStates) {
4058 if (state.item == _plotItem) {
4059 applyZoomTo(state.item, true, true);
4060 } else {
4061 applyZoomTo(state.item, state.item->isXTiedZoom() && tiedX, state.item->isYTiedZoom() && tiedY);
4062 }
4063 }
4064 foreach (ViewItem* item, _viewItems) { // _viewItems is the list of shared axis boxes tied in somehow.
4065 applyZoomTo(item, tiedX, tiedY);
4066 }
4067
4068 kstApp->mainWindow()->document()->setChanged(true);
4069 }
4070
4071
4072 /*
4073 * X axis zoom to FixedExpression, Y axis zoom to FixedExpression.
4074 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4075 void ZoomFixedExpressionCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4076 if (applyX && applyY) {
4077 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4078 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4079 item->setProjectionRect(_fixed);
4080 } else if (applyX) {
4081 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4082 item->setProjectionRect(QRectF(_fixed.x(), item->projectionRect().y(), _fixed.width(), item->projectionRect().height()));
4083 } else if (applyY) {
4084 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4085 item->setProjectionRect(QRectF(item->projectionRect().x(), _fixed.y(), item->projectionRect().width(), _fixed.height()));
4086 }
4087 }
4088
4089
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4090 void ZoomFixedExpressionCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4091 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4092 if (shareBox) {
4093 if (applyX && applyY) {
4094 shareBox->zoomFixedExpression(_fixed, 0);
4095 } else if (applyX) {
4096 shareBox->zoomXRange(_fixed, 0);
4097 } else if (applyY) {
4098 shareBox->zoomYRange(_fixed, 0);
4099 }
4100 }
4101 }
4102
4103
4104 /*
4105 * X axis zoom to Range.
4106 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4107 void ZoomXRangeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4108 Q_UNUSED(applyY);
4109 if (applyX) {
4110 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4111 item->setProjectionRect(QRectF(_fixed.x(), item->projectionRect().y(), _fixed.width(), item->projectionRect().height()));
4112 }
4113 }
4114
4115
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4116 void ZoomXRangeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4117 Q_UNUSED(applyY);
4118 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4119 if (shareBox) {
4120 if (applyX) {
4121 shareBox->zoomXRange(_fixed, 0);
4122 }
4123 }
4124 }
4125
4126
4127 /*
4128 * Y axis zoom to Range.
4129 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4130 void ZoomYRangeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4131 Q_UNUSED(applyX);
4132 if (applyY) {
4133 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4134 item->setProjectionRect(QRectF(item->projectionRect().x(), _fixed.y(), item->projectionRect().width(), _fixed.height()));
4135 }
4136 }
4137
4138
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4139 void ZoomYRangeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4140 Q_UNUSED(applyX);
4141 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4142 if (shareBox) {
4143 if (applyY) {
4144 shareBox->zoomYRange(_fixed, 0);
4145 }
4146 }
4147 }
4148
4149
4150 /*
4151 * X axis zoom to Auto, Y axis zoom to AutoBorder.
4152 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4153 void ZoomMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4154 if (applyX && applyY) {
4155 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4156 item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4157 QRectF compute = item->computedProjectionRect();
4158 item->setProjectionRect(compute);
4159 } else if (applyX) {
4160 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4161 QRectF compute = item->computedProjectionRect();
4162 item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4163 } else if (applyY) {
4164 item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4165 QRectF compute = item->computedProjectionRect();
4166 item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4167 }
4168 }
4169
4170
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4171 void ZoomMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4172 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4173 if (shareBox) {
4174 if (applyX && applyY) {
4175 shareBox->zoomMaximum(0);
4176 } else if (applyX) {
4177 shareBox->zoomXMaximum(0);
4178 } else if (applyY) {
4179 shareBox->zoomYMaximum(0);
4180 }
4181 }
4182 }
4183
4184 /*
4185 * X axis zoom to Auto, Y axis zoom to SpikeInsensitive.
4186 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4187 void ZoomMaxSpikeInsensitiveCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4188 if (applyX && applyY) {
4189 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4190 item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4191 QRectF compute = item->computedProjectionRect();
4192 item->setProjectionRect(compute);
4193 } else if (applyX) {
4194 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4195 QRectF compute = item->computedProjectionRect();
4196 item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4197 } else if (applyY) {
4198 item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4199 QRectF compute = item->computedProjectionRect();
4200 item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4201 }
4202 }
4203
4204
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4205 void ZoomMaxSpikeInsensitiveCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4206 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4207 if (shareBox) {
4208 if (applyX && applyY) {
4209 shareBox->zoomMaxSpikeInsensitive(0);
4210 } else if (applyX) {
4211 shareBox->zoomXMaximum(0);
4212 } else if (applyY) {
4213 shareBox->zoomYNoSpike(0);
4214 }
4215 }
4216 }
4217
4218
4219 /*
4220 * X axis zoom to Auto, Y axis zoom to Mean Centered.
4221 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4222 void ZoomMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4223 if (applyX && applyY) {
4224 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4225 item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4226 QRectF compute = item->computedProjectionRect();
4227 item->setProjectionRect(compute);
4228 } else if (applyX) {
4229 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4230 QRectF compute = item->computedProjectionRect();
4231 item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), compute.width(), item->projectionRect().height()));
4232 } else if (applyY) {
4233 item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4234 QRectF compute = item->computedProjectionRect();
4235 item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), compute.height()));
4236 }
4237 }
4238
4239
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4240 void ZoomMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4241 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4242 if (shareBox) {
4243 if (applyX && applyY) {
4244 shareBox->zoomMeanCentered(0);
4245 } else if (applyX) {
4246 shareBox->zoomXMaximum(0);
4247 } else if (applyY) {
4248 shareBox->zoomMeanCentered(0);
4249 }
4250 }
4251 }
4252
4253 /*
4254 * X axis zoom unchanged, Y axis zoom to Mean Centered.
4255 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4256 void ZoomYMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4257 Q_UNUSED(applyX);
4258
4259 if (applyY) {
4260 item->yAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4261 QRectF compute = item->computedProjectionRect();
4262 item->setProjectionRect(QRectF(item->projectionRect().x(), compute.y(), item->projectionRect().width(), _dY));
4263 }
4264 }
4265
4266
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4267 void ZoomYMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4268 Q_UNUSED(applyX);
4269 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4270 if (shareBox) {
4271 if (applyY) {
4272 shareBox->zoomYMeanCentered(_dY, 0);
4273 }
4274 }
4275 }
4276
4277 /*
4278 * X axis zoom to Mean Centered, Y axis unchanged.
4279 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4280 void ZoomXMeanCenteredCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4281 Q_UNUSED(applyY);
4282
4283 if (applyX) {
4284 item->xAxis()->setAxisZoomMode(PlotAxis::MeanCentered);
4285 QRectF compute = item->computedProjectionRect();
4286 item->setProjectionRect(QRectF(compute.x(), item->projectionRect().y(), _dX, item->projectionRect().height()));
4287 }
4288 }
4289
4290
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4291 void ZoomXMeanCenteredCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4292 Q_UNUSED(applyY);
4293 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4294 if (shareBox) {
4295 if (applyX) {
4296 shareBox->zoomXMeanCentered(0);
4297 }
4298 }
4299 }
4300
4301 /*
4302 * X axis zoom to auto, Y zoom not changed.
4303 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4304 void ZoomXMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4305 Q_UNUSED(applyY);
4306 if (applyX) {
4307 item->xAxis()->setAxisZoomMode(PlotAxis::Auto);
4308 QRectF compute = item->computedProjectionRect();
4309 item->setProjectionRect(QRectF(compute.x(),
4310 item->projectionRect().y(),
4311 compute.width(),
4312 item->projectionRect().height()));
4313 }
4314 }
4315
4316
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4317 void ZoomXMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4318 Q_UNUSED(applyY);
4319 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4320 if (shareBox) {
4321 if (applyX) {
4322 shareBox->zoomXMaximum(0);
4323 }
4324 }
4325 }
4326
4327
4328 /*
4329 * X axis zoom to auto border, Y zoom not changed.
4330 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4331 void ZoomXAutoBorderCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4332 Q_UNUSED(applyY);
4333 if (applyX) {
4334 item->xAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4335 QRectF compute = item->computedProjectionRect();
4336 item->setProjectionRect(QRectF(compute.x(),
4337 item->projectionRect().y(),
4338 compute.width(),
4339 item->projectionRect().height()));
4340 }
4341 }
4342
4343
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4344 void ZoomXAutoBorderCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4345 Q_UNUSED(applyY);
4346 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4347 if (shareBox) {
4348 if (applyX) {
4349 shareBox->zoomXAutoBorder(0);
4350 }
4351 }
4352 }
4353
4354
4355 /*
4356 * X axis zoom to no spike, Y zoom not changed.
4357 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4358 void ZoomXNoSpikeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4359 Q_UNUSED(applyY);
4360 if (applyX) {
4361 item->xAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4362 QRectF compute = item->computedProjectionRect();
4363 item->setProjectionRect(QRectF(compute.x(),
4364 item->projectionRect().y(),
4365 compute.width(),
4366 item->projectionRect().height()));
4367 }
4368 }
4369
4370
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4371 void ZoomXNoSpikeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4372 Q_UNUSED(applyY);
4373 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4374 if (shareBox) {
4375 if (applyX) {
4376 shareBox->zoomXNoSpike(0);
4377 }
4378 }
4379 }
4380
4381
4382 /*
4383 * X axis zoom changed to fixed and shifted to right:
4384 * new_xmin = xmin + (xmax - xmin)*0.10;
4385 * new_xmax = xmax + (xmax – xmin)*0.10;
4386 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4387 void ZoomXRightCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4388 Q_UNUSED(applyY);
4389 if (applyX) {
4390 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4391
4392 QRectF compute = item->projectionRect();
4393
4394 qreal dx = (item->xMax() - item->xMin())*0.10;
4395 if (item->xAxis()->axisReversed()) {
4396 dx *=-1;
4397 }
4398 if (item->xAxis()->axisLog()) {
4399 compute.setLeft(pow(10, item->xMin() + dx));
4400 compute.setRight(pow(10, item->xMax() + dx));
4401 } else {
4402 compute.setLeft(compute.left() + dx);
4403 compute.setRight(compute.right() + dx);
4404 }
4405
4406 item->setProjectionRect(compute);
4407 }
4408 }
4409
4410
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4411 void ZoomXRightCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4412 Q_UNUSED(applyY);
4413 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4414 if (shareBox) {
4415 if (applyX) {
4416 shareBox->zoomXRight(0);
4417 }
4418 }
4419 }
4420
4421 /*
4422 * X axis zoom changed to fixed and shifted to right:
4423 * new_xmin = xmin + (xmax - xmin);
4424 * new_xmax = xmax + (xmax – xmin);
4425 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4426 void ZoomXFarRightCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4427 Q_UNUSED(applyY);
4428 if (applyX) {
4429 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4430
4431 QRectF compute = item->projectionRect();
4432
4433 qreal dx = (item->xMax() - item->xMin());
4434 if (item->xAxis()->axisReversed()) {
4435 dx *=-1;
4436 }
4437 if (item->xAxis()->axisLog()) {
4438 compute.setLeft(pow(10, item->xMin() + dx));
4439 compute.setRight(pow(10, item->xMax() + dx));
4440 } else {
4441 compute.setLeft(compute.left() + dx);
4442 compute.setRight(compute.right() + dx);
4443 }
4444
4445 item->setProjectionRect(compute);
4446 }
4447 }
4448
4449
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4450 void ZoomXFarRightCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4451 Q_UNUSED(applyY);
4452 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4453 if (shareBox) {
4454 if (applyX) {
4455 shareBox->zoomXRight(0, true);
4456 }
4457 }
4458 }
4459
4460 /*
4461 * X axis zoom changed to fixed and shifted to :
4462 * new_xmin = xmin - (xmax - xmin)*0.10;
4463 * new_xmax = xmax - (xmax – xmin)*0.10;
4464 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4465 void ZoomXLeftCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4466 Q_UNUSED(applyY);
4467 if (applyX) {
4468 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4469
4470 QRectF compute = item->projectionRect();
4471
4472 qreal dx = (item->xMax() - item->xMin())*0.10;
4473 if (item->xAxis()->axisReversed()) {
4474 dx *=-1;
4475 }
4476 if (item->xAxis()->axisLog()) {
4477 compute.setLeft(pow(10, item->xMin() - dx));
4478 compute.setRight(pow(10, item->xMax() - dx));
4479 } else {
4480 compute.setLeft(compute.left() - dx);
4481 compute.setRight(compute.right() - dx);
4482 }
4483
4484 item->setProjectionRect(compute);
4485 }
4486 }
4487
4488
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4489 void ZoomXLeftCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4490 Q_UNUSED(applyY);
4491 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4492 if (shareBox) {
4493 if (applyX) {
4494 shareBox->zoomXLeft(0);
4495 }
4496 }
4497 }
4498
4499 /*
4500 * X axis zoom changed to fixed and shifted to :
4501 * new_xmin = xmin - (xmax - xmin);
4502 * new_xmax = xmax - (xmax – xmin);
4503 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4504 void ZoomXFarLeftCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4505 Q_UNUSED(applyY);
4506 if (applyX) {
4507 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4508
4509 QRectF compute = item->projectionRect();
4510
4511 qreal dx = (item->xMax() - item->xMin());
4512 if (item->xAxis()->axisReversed()) {
4513 dx *=-1;
4514 }
4515 if (item->xAxis()->axisLog()) {
4516 compute.setLeft(pow(10, item->xMin() - dx));
4517 compute.setRight(pow(10, item->xMax() - dx));
4518 } else {
4519 compute.setLeft(compute.left() - dx);
4520 compute.setRight(compute.right() - dx);
4521 }
4522
4523 item->setProjectionRect(compute);
4524 }
4525 }
4526
4527
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4528 void ZoomXFarLeftCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4529 Q_UNUSED(applyY);
4530 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4531 if (shareBox) {
4532 if (applyX) {
4533 shareBox->zoomXLeft(0, true);
4534 }
4535 }
4536 }
4537
4538
4539 /*
4540 * X axis zoom changed to fixed and increased:
4541 * new_xmin = xmin - (xmax - xmin)*0.25;
4542 * new_xmax = xmax + (xmax – xmin)*0.25;
4543 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4544 void ZoomXOutCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4545 Q_UNUSED(applyY);
4546 if (applyX) {
4547 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4548
4549 QRectF compute = item->projectionRect();
4550
4551 qreal dx = (item->xMax() - item->xMin())*0.25;
4552 if (item->xAxis()->axisLog()) {
4553 compute.setLeft(pow(10, item->xMin() - dx));
4554 compute.setRight(pow(10, item->xMax() + dx));
4555 } else {
4556 compute.setLeft(compute.left() - dx);
4557 compute.setRight(compute.right() + dx);
4558 }
4559
4560 item->setProjectionRect(compute);
4561 // item->update();
4562 }
4563 }
4564
4565
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4566 void ZoomXOutCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4567 Q_UNUSED(applyY);
4568 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4569 if (shareBox) {
4570 if (applyX) {
4571 shareBox->zoomXOut(0);
4572 }
4573 }
4574 }
4575
4576
4577 /*
4578 * X axis zoom changed to fixed and decreased:
4579 * new_xmin = xmin + (xmax - xmin)*0.1666666;
4580 * new_xmax = xmax - (xmax – xmin)*0.1666666;
4581 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4582 void ZoomXInCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4583 Q_UNUSED(applyY);
4584 if (applyX) {
4585 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4586
4587 QRectF compute = item->projectionRect();
4588
4589 qreal dx = (item->xMax() - item->xMin())*0.1666666;
4590 if (item->xAxis()->axisLog()) {
4591 compute.setLeft(pow(10, item->xMin() + dx));
4592 compute.setRight(pow(10, item->xMax() - dx));
4593 } else {
4594 compute.setLeft(compute.left() + dx);
4595 compute.setRight(compute.right() - dx);
4596 }
4597
4598 item->setProjectionRect(compute);
4599 }
4600 }
4601
4602
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4603 void ZoomXInCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4604 Q_UNUSED(applyY);
4605 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4606 if (shareBox) {
4607 if (applyX) {
4608 shareBox->zoomXIn(0);
4609 }
4610 }
4611 }
4612
4613
4614 /*
4615 * Normalize X axis to Y axis: Given the current plot aspect ratio, change
4616 * the X axis range to have the same units per mm as the Y axis range. Particularly
4617 * useful for images.
4618 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4619 void ZoomNormalizeXToYCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4620 Q_UNUSED(applyY);
4621 if (applyX) {
4622 QRectF compute = item->projectionRect();
4623 qreal mean = compute.center().x();
4624 qreal range = item->plotRect().width() * compute.height() / item->plotRect().height();
4625
4626 compute.setLeft(mean - (range / 2.0));
4627 compute.setRight(mean + (range / 2.0));
4628
4629 item->xAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4630 item->setProjectionRect(compute);
4631 }
4632 }
4633
4634
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4635 void ZoomNormalizeXToYCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4636 Q_UNUSED(applyY);
4637 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4638 if (shareBox) {
4639 if (applyX) {
4640 shareBox->zoomNormalizeXtoY(0);
4641 }
4642 }
4643 }
4644
4645
4646 /*
4647 * When zoomed in in X, auto zoom Y, only
4648 * counting points within the current X range. (eg, curve goes from x=0 to 100, but
4649 * we are zoomed in to x = 30 to 40. Adjust Y zoom to include all points with x
4650 * values between 30 and 40.
4651 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4652 void ZoomYLocalMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4653 Q_UNUSED(applyX);
4654 if (applyY) {
4655 double minimum = item->yMax();
4656 double maximum = item->yMin();
4657 item->computedRelationalMax(minimum, maximum);
4658
4659 item->computeBorder(Qt::Vertical, minimum, maximum);
4660
4661 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4662
4663 QRectF compute = item->projectionRect();
4664 compute.setTop(minimum);
4665 compute.setBottom(maximum);
4666
4667 item->setProjectionRect(compute);
4668 }
4669 }
4670
4671
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4672 void ZoomYLocalMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4673 Q_UNUSED(applyX);
4674 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4675 if (shareBox) {
4676 if (applyY) {
4677 shareBox->zoomYLocalMaximum(0);
4678 }
4679 }
4680 }
4681
4682
4683 /*
4684 * Y axis zoom to auto, X zoom not changed.
4685 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4686 void ZoomYMaximumCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4687 Q_UNUSED(applyX);
4688 if (applyY) {
4689 item->yAxis()->setAxisZoomMode(PlotAxis::Auto);
4690 QRectF compute = item->computedProjectionRect();
4691 item->setProjectionRect(QRectF(item->projectionRect().x(),
4692 compute.y(),
4693 item->projectionRect().width(),
4694 compute.height()));
4695 }
4696 }
4697
4698
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4699 void ZoomYMaximumCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4700 Q_UNUSED(applyX);
4701 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4702 if (shareBox) {
4703 if (applyY) {
4704 shareBox->zoomYMaximum(0);
4705 }
4706 }
4707 }
4708
4709
4710 /*
4711 * Y axis zoom to auto border, X zoom not changed.
4712 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4713 void ZoomYAutoBorderCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4714 Q_UNUSED(applyX);
4715 if (applyY) {
4716 item->yAxis()->setAxisZoomMode(PlotAxis::AutoBorder);
4717 QRectF compute = item->computedProjectionRect();
4718 item->setProjectionRect(QRectF(item->projectionRect().x(),
4719 compute.y(),
4720 item->projectionRect().width(),
4721 compute.height()));
4722 }
4723 }
4724
4725
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4726 void ZoomYAutoBorderCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4727 Q_UNUSED(applyX);
4728 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4729 if (shareBox) {
4730 if (applyY) {
4731 shareBox->zoomYAutoBorder(0);
4732 }
4733 }
4734 }
4735
4736
4737 /*
4738 * Y axis zoom to no spike, X zoom not changed.
4739 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4740 void ZoomYNoSpikeCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4741 Q_UNUSED(applyX);
4742 if (applyY) {
4743 item->yAxis()->setAxisZoomMode(PlotAxis::SpikeInsensitive);
4744 QRectF compute = item->computedProjectionRect();
4745 item->setProjectionRect(QRectF(item->projectionRect().x(),
4746 compute.y(),
4747 item->projectionRect().width(),
4748 compute.height()));
4749 }
4750 }
4751
4752
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4753 void ZoomYNoSpikeCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4754 Q_UNUSED(applyX);
4755 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4756 if (shareBox) {
4757 if (applyY) {
4758 shareBox->zoomYNoSpike(0);
4759 }
4760 }
4761 }
4762
4763
4764 /*
4765 * Y axis zoom up. If the Y zoom mode is not
4766 * Mean Centered, change to Fixed (expression).
4767 * new_ymin = ymin + (ymax - ymin)*0.1;
4768 * new_ymax = ymax + (ymax - ymin)*0.1;
4769 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4770 void ZoomYUpCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4771 Q_UNUSED(applyX);
4772 if (applyY) {
4773 if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4774 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4775
4776 QRectF compute = item->projectionRect();
4777
4778 qreal dy = (item->yMax() - item->yMin())*0.1;
4779 if (item->yAxis()->axisLog()) {
4780 compute.setTop(pow(10, item->yMin() + dy));
4781 compute.setBottom(pow(10, item->yMax() + dy));
4782 } else {
4783 compute.setTop(compute.top() + dy);
4784 compute.setBottom(compute.bottom() + dy);
4785 }
4786
4787 item->setProjectionRect(compute);
4788 }
4789 }
4790
4791
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4792 void ZoomYUpCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4793 Q_UNUSED(applyX);
4794 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4795 if (shareBox) {
4796 if (applyY) {
4797 shareBox->zoomYUp(0);
4798 }
4799 }
4800 }
4801
4802
4803 /*
4804 * Y axis zoom down. If the Y zoom mode is not
4805 * Mean Centered, change to Fixed (expression).
4806 * new_ymin = ymin - (ymax - ymin)*0.10;
4807 * new_ymax = ymax - (ymax - ymin)*0.10;
4808 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4809 void ZoomYDownCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4810 Q_UNUSED(applyX);
4811 if (applyY) {
4812 if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4813 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4814
4815 QRectF compute = item->projectionRect();
4816
4817 qreal dy = (item->yMax() - item->yMin())*0.1;
4818 if (item->yAxis()->axisLog()) {
4819 compute.setTop(pow(10, item->yMin() - dy));
4820 compute.setBottom(pow(10, item->yMax() - dy));
4821 } else {
4822 compute.setTop(compute.top() - dy);
4823 compute.setBottom(compute.bottom() - dy);
4824 }
4825
4826 item->setProjectionRect(compute);
4827 }
4828 }
4829
4830
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4831 void ZoomYDownCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4832 Q_UNUSED(applyX);
4833 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4834 if (shareBox) {
4835 if (applyY) {
4836 shareBox->zoomYDown(0);
4837 }
4838 }
4839 }
4840
4841
4842 /*
4843 * Y axis zoom increased. If the Y zoom mode is not
4844 * Mean Centered, change to Fixed (expression).
4845 * new_ymin = ymin - (ymax - ymin)*0.25;
4846 * new_ymax = ymax + (ymax - ymin)*0.25;
4847 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4848 void ZoomYOutCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4849 Q_UNUSED(applyX);
4850 if (applyY) {
4851 if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4852 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4853
4854 QRectF compute = item->projectionRect();
4855
4856 qreal dy = (item->yMax() - item->yMin())*0.25;
4857 if (item->yAxis()->axisLog()) {
4858 compute.setTop(pow(10, item->yMin() - dy));
4859 compute.setBottom(pow(10, item->yMax() + dy));
4860 } else {
4861 compute.setTop(compute.top() - dy);
4862 compute.setBottom(compute.bottom() + dy);
4863 }
4864
4865 item->setProjectionRect(compute);
4866 // item->update();
4867 }
4868 }
4869
4870
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4871 void ZoomYOutCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4872 Q_UNUSED(applyX);
4873 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4874 if (shareBox) {
4875 if (applyY) {
4876 shareBox->zoomYOut(0);
4877 }
4878 }
4879 }
4880
4881
4882 /*
4883 * Y axis zoom decreased. If the Y zoom mode is not
4884 * Mean Centered, change to Fixed (expression).
4885 * new_ymin = ymin + (ymax - ymin)*0.1666666;
4886 * new_ymax = ymax - (ymax – ymin)*0.1666666;
4887 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4888 void ZoomYInCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4889 Q_UNUSED(applyX);
4890 if (applyY) {
4891 if (item->yAxis()->axisZoomMode() != PlotAxis::MeanCentered)
4892 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4893
4894 QRectF compute = item->projectionRect();
4895
4896 qreal dy = (item->yMax() - item->yMin())*0.1666666;
4897 if (item->yAxis()->axisLog()) {
4898 compute.setTop(pow(10, item->yMin() + dy));
4899 compute.setBottom(pow(10, item->yMax() - dy));
4900 } else {
4901 compute.setTop(compute.top() + dy);
4902 compute.setBottom(compute.bottom() - dy);
4903 }
4904
4905 item->setProjectionRect(compute);
4906 // item->update();
4907 }
4908 }
4909
4910
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4911 void ZoomYInCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4912 Q_UNUSED(applyX);
4913 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4914 if (shareBox) {
4915 if (applyY) {
4916 shareBox->zoomYIn(0);
4917 }
4918 }
4919 }
4920
4921
4922 /*
4923 * Normalize Y axis to X axis: Given the current plot aspect ratio,
4924 * change the Y axis range to have the same units per mm as the X axis range.
4925 * Particularly useful for images.
4926 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4927 void ZoomNormalizeYToXCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4928 Q_UNUSED(applyX);
4929 if (applyY) {
4930 QRectF compute = item->projectionRect();
4931 qreal mean = compute.center().y();
4932 qreal range = item->plotRect().height() * compute.width() / item->plotRect().width();
4933
4934 compute.setTop(mean - (range / 2.0));
4935 compute.setBottom(mean + (range / 2.0));
4936
4937 item->yAxis()->setAxisZoomMode(PlotAxis::FixedExpression);
4938 item->setProjectionRect(compute);
4939 }
4940 }
4941
4942
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4943 void ZoomNormalizeYToXCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4944 Q_UNUSED(applyX);
4945 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4946 if (shareBox) {
4947 if (applyY) {
4948 shareBox->zoomNormalizeYtoX(0);
4949 }
4950 }
4951 }
4952
4953
4954 /*
4955 * Switch the X Axis to a Log Scale.
4956 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4957 void ZoomXLogCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4958 Q_UNUSED(applyY);
4959 if (applyX) {
4960 item->xAxis()->setAxisLog(_enableLog);
4961 item->setProjectionRect(item->computedProjectionRect(), true); //need to recompute
4962 }
4963 }
4964
4965
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4966 void ZoomXLogCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4967 Q_UNUSED(applyY);
4968 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4969 if (shareBox) {
4970 if (applyX) {
4971 shareBox->zoomLogX(0, false, _enableLog);
4972 }
4973 }
4974 }
4975
4976
4977 /*
4978 * Switch the Y Axis to a Log Scale.
4979 */
applyZoomTo(PlotItem * item,bool applyX,bool applyY)4980 void ZoomYLogCommand::applyZoomTo(PlotItem *item, bool applyX, bool applyY) {
4981 Q_UNUSED(applyX);
4982 if (applyY) {
4983 item->yAxis()->setAxisLog(_enableLog);
4984 item->setProjectionRect(item->computedProjectionRect(), true); //need to recompute
4985 }
4986 }
4987
4988
applyZoomTo(ViewItem * item,bool applyX,bool applyY)4989 void ZoomYLogCommand::applyZoomTo(ViewItem *item, bool applyX, bool applyY) {
4990 Q_UNUSED(applyX);
4991 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(item);
4992 if (shareBox) {
4993 if (applyY) {
4994 shareBox->zoomLogY(0, false, _enableLog);
4995 }
4996 }
4997 }
4998
4999 }
5000
5001 // vim: ts=2 sw=2 et
5002