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