Main Page · Modules · All Classes · Class Hierarchy
MPDiagram.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ 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  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MPDiagram.hpp"
23 
24 #include <qwt_legend.h>
25 #include <qwt_plot_marker.h>
26 #include <qwt_scale_widget.h>
27 #include <qwt_text_label.h>
28 
29 #include <qlayout.h>
30 
31 #include <boost/scoped_ptr.hpp>
32 
33 QwtText MPTimeScaleDraw::label(double value) const
34 {
35  QString NumberStr;
36 
37  NumberStr.sprintf("%1.2f", value);
38  if (NumberStr.endsWith(QLatin1String(".00")))
39  {
40  NumberStr.remove(NumberStr.size()-3, 3);
41  }
42  QwtText Text(NumberStr);
43 
44  Text.setColor(Qt::black);
45  return Text;
46 }
47 
48 
49 MPPlotCurve::MPPlotCurve() : QwtPlotCurve()
50 {
51  setRenderHint(QwtPlotItem::RenderAntialiased);
52  setLegendAttribute(QwtPlotCurve::LegendShowLine, true);
53  // Make the line legend item longer than the default
54  setLegendIconSize(QSize(20, 5));
55  setStyle(QwtPlotCurve::Lines);
56 }
57 
58 
59 void MPLegendLabel::drawText(QPainter* painter, const QRectF& rect)
60 {
61  QRectF newRect(rect);
62 
63  // Does this defect only occur on Ubuntu where Qt4 and Qt5 live together?
64 #if defined(__unix__) && !defined(__ANDROID__)
65  // Fix the vertical alignment problem of the legend labels,
66  if (text().text().contains("<sub>"))
67  {
68  newRect.setY(newRect.y()-14);
69  } else {
70  newRect.setY(newRect.y()-6);
71  }
72 #endif
73  QwtTextLabel::drawText(painter, newRect);
74 }
75 
76 
77 void MPLegendLabel::paintEvent(QPaintEvent* event)
78 {
79  // Don't paint the clicked state
80  if (isDown())
81  {
82  setDown(false);
83  }
84  QwtLegendLabel::paintEvent(event);
85 }
86 
87 
88 QWidget* MPLegend::createWidget(const QwtLegendData& legend_data) const
89 {
90  QwtLegendLabel* Label = new MPLegendLabel();
91 
92  // Remove all margins and indents to spare space on the UI
93  Label->setMargin(0);
94  Label->setIndent(0);
95  Label->setItemMode(defaultItemMode());
96  Label->setData(legend_data);
97  connect(Label, SIGNAL(clicked()), SLOT(itemClicked()));
98  connect(Label, SIGNAL(checked(bool)), SLOT(itemChecked(bool)));
99  return Label;
100 }
101 
102 
103 MPDiagram::MPDiagram(bool enable_legend) : QwtPlot(), MinorTicksGrid(new QwtPlotGrid),
104  MajorTicksGrid(new QwtPlotGrid)
105 {
106  if (enable_legend)
107  {
108  insertLegend(new MPLegend(), QwtPlot::TopLegend);
109  QWidget* ContentsWidget = static_cast<QwtLegend*>(legend())->contentsWidget();
110 #if defined(__ANDROID__)
111  boost::scoped_ptr<QFont> Font(new QFont("Courier New", 7));
112 
113  setAxisFont(QwtPlot::xBottom, *Font);
114  setAxisFont(QwtPlot::yLeft, *Font);
115  boost::scoped_ptr<QFont> TitleFont(new QFont("Courier New", 8, QFont::Bold));
116  QwtText Title;
117 
118  Title.setFont(*TitleFont);
119  setAxisTitle(QwtPlot::xBottom, Title);
120  ContentsWidget->setStyleSheet(ContentsWidget->styleSheet()+" QWidget { font: 8pt \"Courier New\"; }");
121 #else
122  ContentsWidget->setStyleSheet(ContentsWidget->styleSheet()+" QWidget { font: 10.5pt \"Courier New\"; }");
123 #endif
124  // Remove the spacing between the legend elements
125  ContentsWidget->layout()->setMargin(0);
126  ContentsWidget->layout()->setSpacing(0);
127  }
128  setContentsMargins(10, 10, 10, 10);
129  // Set helper grids
130  MinorTicksGrid->setMajorPen(QPen(Qt::gray, 0, Qt::DotLine));
131  MinorTicksGrid->setMinorPen(QPen(Qt::gray, 0, Qt::DotLine));
132  MinorTicksGrid->attach(this);
133  SetMinorGridEnabled(true);
134  MajorTicksGrid->setMajorPen(QPen(Qt::black, 0, Qt::DotLine));
135  MajorTicksGrid->attach(this);
136  SetMajorGridEnabled(true);
137  // Set axis
138  QwtText AxisTitle = axisTitle(QwtPlot::xBottom);
139 
140  AxisTitle.setColor(Qt::black);
141  setAxisTitle(QwtPlot::xBottom, AxisTitle);
142  setAxisScaleDraw(QwtPlot::xBottom, new MPTimeScaleDraw);
143  setAxisScaleDraw(QwtPlot::yLeft, new MPTimeScaleDraw);
144  axisWidget(QwtPlot::xBottom)->setPalette(Qt::white);
145  axisWidget(QwtPlot::yLeft)->setPalette(Qt::white);
146 }
147 
148 
150 {
151  for (auto iter = MissingDataMarkers.begin(); iter != MissingDataMarkers.end(); ++iter)
152  {
153  iter.value()->detach();
154  delete iter.value();
155  }
156  MissingDataMarkers.clear();
157  for (auto iter = StickMarkers.begin(); iter != StickMarkers.end(); ++iter)
158  {
159  iter.value()->detach();
160  delete iter.value();
161  }
162  StickMarkers.clear();
163 }
164 
165 
166 void MPDiagram::SetHorizontalTicks(double first, double last)
167 {
168  QList<double> Ticks;
169 
170  for (int i = 0; i <= 10; ++i)
171  {
172  Ticks.push_back(first+i*(last-first) / 10);
173  }
174  QwtScaleDiv ScaleDiv = axisScaleDiv(QwtPlot::xBottom);
175 
176  ScaleDiv.setTicks(QwtScaleDiv::MajorTick, Ticks);
177  Ticks.clear();
178  for (int i = 0; i <= 40; ++i)
179  {
180  Ticks.push_back(first+i*(last-first) / 40);
181  }
182  ScaleDiv.setTicks(QwtScaleDiv::MinorTick, Ticks);
183  setAxisScaleDiv(QwtPlot::xBottom, ScaleDiv);
184  MinorTicksGrid->setXDiv(ScaleDiv);
185  MajorTicksGrid->setXDiv(ScaleDiv);
186 }
187 
188 
189 void MPDiagram::SetVerticalTicks(double first, double last)
190 {
191  QList<double> Ticks;
192 
193  for (int i = 0; i <= 10; ++i)
194  {
195  Ticks.push_back(first+i*(last-first) / 10);
196  }
197  QwtScaleDiv ScaleDiv = axisScaleDiv(QwtPlot::yLeft);
198 
199  ScaleDiv.setTicks(QwtScaleDiv::MajorTick, Ticks);
200  Ticks.clear();
201  ScaleDiv.setTicks(QwtScaleDiv::MediumTick, Ticks);
202  Ticks.clear();
203  ScaleDiv.setTicks(QwtScaleDiv::MinorTick, Ticks);
204  setAxisScaleDiv(QwtPlot::yLeft, ScaleDiv);
205  MinorTicksGrid->setYDiv(ScaleDiv);
206  MajorTicksGrid->setYDiv(ScaleDiv);
207 }
208 
209 
210 void MPDiagram::SetMinorGridEnabled(bool new_state)
211 {
212  if (new_state)
213  {
214  MinorTicksGrid->enableX(true);
215  MinorTicksGrid->enableY(true);
216  MinorTicksGrid->enableXMin(false);
217  MinorTicksGrid->enableYMin(true);
218  } else {
219  MinorTicksGrid->enableX(false);
220  MinorTicksGrid->enableY(false);
221  MinorTicksGrid->enableXMin(false);
222  MinorTicksGrid->enableYMin(false);
223  }
224 }
225 
226 
227 void MPDiagram::SetMajorGridEnabled(bool new_state)
228 {
229  if (new_state)
230  {
231  MajorTicksGrid->enableX(false);
232  MajorTicksGrid->enableY(true);
233  MajorTicksGrid->enableXMin(false);
234  MajorTicksGrid->enableYMin(false);
235  } else {
236  MajorTicksGrid->enableX(false);
237  MajorTicksGrid->enableY(false);
238  MajorTicksGrid->enableXMin(false);
239  MajorTicksGrid->enableYMin(false);
240  }
241 }
242 
243 
244 QwtPlotMarker* MPDiagram::AddMissingDataMarker(float value)
245 {
246  if (MissingDataMarkers.contains(value))
247  return MissingDataMarkers[value];
248 
249  QwtPlotMarker* NewMarker = new QwtPlotMarker();
250 
251  NewMarker->setLineStyle(QwtPlotMarker::VLine);
252  NewMarker->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
253  NewMarker->setLinePen(QPen(QColor(0x90, 0x90, 0x90), 0, Qt::DashLine));
254  NewMarker->setValue(value, 0.0);
255  NewMarker->attach(this);
256  MissingDataMarkers.insert(value, NewMarker);
257  return NewMarker;
258 }
259 
260 
261 QwtPlotMarker* MPDiagram::AddStickMarker(float value, const QColor& color, bool big_stick)
262 {
263  if (StickMarkers.contains(value))
264  return StickMarkers[value];
265 
266  QwtPlotMarker* NewMarker = new QwtPlotMarker();
267 
268  if (big_stick)
269  NewMarker->setLineStyle(QwtPlotMarker::VDoubleStick);
270  else
271  NewMarker->setLineStyle(QwtPlotMarker::VStick);
272  NewMarker->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
273  NewMarker->setLinePen(QPen(color, 0, Qt::SolidLine));
274  NewMarker->setValue(value, 0.0);
275  NewMarker->attach(this);
276  StickMarkers.insert(value, NewMarker);
277  return NewMarker;
278 }
279 
280 
281 void MPDiagram::RemoveMissingDataMarker(float value)
282 {
283  auto Iter = MissingDataMarkers.find(value);
284 
285  if (Iter == MissingDataMarkers.end())
286  return;
287 
288  Iter.value()->detach();
289  delete Iter.value();
290  MissingDataMarkers.erase(Iter);
291 }
292 
293 
294 void MPDiagram::RemoveStickMarker(float value)
295 {
296  auto Iter = StickMarkers.find(value);
297 
298  if (Iter == StickMarkers.end())
299  return;
300 
301  Iter.value()->detach();
302  delete Iter.value();
303  StickMarkers.erase(Iter);
304 }
virtual ~MPDiagram()
Class destructor.
Definition: MPDiagram.cpp:149
MP::TimestampMarkerMap StickMarkers
Stick marker list.
Definition: MPDiagram.hpp:120
Legend label on QwtLegendLabel.
Definition: MPDiagram.hpp:75
Legend based on QwtLegend.
Definition: MPDiagram.hpp:86
QwtPlotGrid * MinorTicksGrid
Helper grid for the minor ticks.
Definition: MPDiagram.hpp:122
MP::TimestampMarkerMap MissingDataMarkers
Missing data marker list.
Definition: MPDiagram.hpp:118
Time scale draw based on QwtScaleDraw.
Definition: MPDiagram.hpp:58
MPDiagram(bool enable_legend=true)
Class constructor.
Definition: MPDiagram.cpp:103
QwtPlotGrid * MajorTicksGrid
Helper grid for the major ticks.
Definition: MPDiagram.hpp:124