LeechCraft  0.6.70-13729-g7046a9d2a7
Modular cross-platform feature rich live environment.
plotitem.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "plotitem.h"
31 #include <cmath>
32 #include <limits>
33 #include <vector>
34 #include <memory>
35 #include <QStyleOption>
36 #include <QColor>
37 #include <qwt_plot.h>
38 #include <qwt_plot_curve.h>
39 #include <qwt_plot_renderer.h>
40 #include <qwt_plot_grid.h>
41 #include <qwt_scale_draw.h>
42 #include <qwt_text_label.h>
43 #include <qwt_plot_canvas.h>
44 
46 
47 namespace LC
48 {
49 namespace Util
50 {
51  PlotItem::PlotItem (QQuickItem *parent)
52  : QQuickPaintedItem { parent }
53  , Color_ { "#FF4B10" }
54  {
55  setFlag (ItemHasContents, true);
56  }
57 
59  {
60  return Points_;
61  }
62 
64  {
65  if (pts == Points_)
66  return;
67 
68  Points_ = pts;
69  emit pointsChanged ();
70  update ();
71  }
72 
73  QVariant PlotItem::GetMultipoints () const
74  {
75  QVariantList result;
76  for (const auto& set : Multipoints_)
77  {
78  QVariantMap map
79  {
80  { "color", QVariant::fromValue (set.Color_) },
81  { "points", QVariant::fromValue (set.Points_) }
82  };
83 
84  if (set.BrushColor_)
85  map ["brushColor"] = *set.BrushColor_;
86 
87  result << map;
88  }
89  return result;
90  }
91 
92  void PlotItem::SetMultipoints (const QVariant& variant)
93  {
94  Multipoints_.clear ();
95 
96  for (const auto& set : variant.toList ())
97  {
98  const auto& map = set.toMap ();
99 
100  const auto& colorVar = map ["color"];
101  const auto& pointsVar = map ["points"];
102 
103  boost::optional<QColor> brushColor;
104  if (map.contains ("brushColor"))
105  {
106  const auto& brushVar = map ["brushColor"];
107  if (!brushVar.canConvert<QString> ())
108  qWarning () << Q_FUNC_INFO
109  << "invalid brush color"
110  << brushVar;
111  else
112  brushColor = QColor { brushVar.toString () };
113  }
114 
115  if (!colorVar.canConvert<QString> () ||
116  !pointsVar.canConvert<QList<QPointF>> ())
117  {
118  qWarning () << Q_FUNC_INFO
119  << "invalid map"
120  << map;
121  qWarning () << Q_FUNC_INFO
122  << "ignoring this point";
123  continue;
124  }
125 
126  Multipoints_.append ({
127  map ["color"].toString (),
128  brushColor,
129  map ["points"].value<QList<QPointF>> ()
130  });
131  }
132  update ();
133  }
134 
135  double PlotItem::GetMinXValue () const
136  {
137  return MinXValue_;
138  }
139 
140  void PlotItem::SetMinXValue (double val)
141  {
142  SetNewValue (val, MinXValue_, [this] { emit minXValueChanged (); });
143  }
144 
145  double PlotItem::GetMaxXValue () const
146  {
147  return MaxXValue_;
148  }
149 
150  void PlotItem::SetMaxXValue (double val)
151  {
152  SetNewValue (val, MaxXValue_, [this] { emit maxXValueChanged (); });
153  }
154 
155  double PlotItem::GetMinYValue () const
156  {
157  return MinYValue_;
158  }
159 
160  void PlotItem::SetMinYValue (double val)
161  {
162  SetNewValue (val, MinYValue_, [this] { emit minYValueChanged (); });
163  }
164 
165  double PlotItem::GetMaxYValue () const
166  {
167  return MaxYValue_;
168  }
169 
170  void PlotItem::SetMaxYValue (double val)
171  {
172  SetNewValue (val, MaxYValue_, [this] { emit maxYValueChanged (); });
173  }
174 
176  {
177  return YGridEnabled_;
178  }
179 
181  {
182  SetNewValue (val, YGridEnabled_, [this] { emit yGridChanged (); });
183  }
184 
186  {
187  return YMinorGridEnabled_;
188  }
189 
191  {
192  SetNewValue (val, YMinorGridEnabled_, [this] { emit yMinorGridChanged (); });
193  }
194 
195  double PlotItem::GetAlpha () const
196  {
197  return Alpha_;
198  }
199 
200  void PlotItem::SetAlpha (double a)
201  {
202  Alpha_ = a;
203  emit alphaChanged ();
204  }
205 
206  QColor PlotItem::GetColor () const
207  {
208  return Color_;
209  }
210 
211  void PlotItem::SetColor (const QColor& color)
212  {
213  SetNewValue (color, Color_, [this] { emit colorChanged (); });
214  }
215 
217  {
218  return LeftAxisEnabled_;
219  }
220 
221  void PlotItem::SetLeftAxisEnabled (bool enabled)
222  {
223  SetNewValue (enabled, LeftAxisEnabled_, [this] { emit leftAxisEnabledChanged (); });
224  }
225 
227  {
228  return BottomAxisEnabled_;
229  }
230 
231  void PlotItem::SetBottomAxisEnabled (bool enabled)
232  {
233  SetNewValue (enabled, BottomAxisEnabled_, [this] { emit bottomAxisEnabledChanged (); });
234  }
235 
236  QString PlotItem::GetLeftAxisTitle () const
237  {
238  return LeftAxisTitle_;
239  }
240 
241  void PlotItem::SetLeftAxisTitle (const QString& title)
242  {
243  SetNewValue (title, LeftAxisTitle_, [this] { emit leftAxisTitleChanged (); });
244  }
245 
247  {
248  return BottomAxisTitle_;
249  }
250 
251  void PlotItem::SetBottomAxisTitle (const QString& title)
252  {
253  SetNewValue (title, BottomAxisTitle_, [this] { emit bottomAxisTitleChanged (); });
254  }
255 
256  QString PlotItem::GetPlotTitle () const
257  {
258  return PlotTitle_;
259  }
260 
261  void PlotItem::SetPlotTitle (const QString& title)
262  {
263  SetNewValue (title, PlotTitle_, [this] { emit plotTitleChanged (); });
264  }
265 
266  QColor PlotItem::GetBackground () const
267  {
268  return BackgroundColor_;
269  }
270 
271  void PlotItem::SetBackground (const QColor& bg)
272  {
273  SetNewValue (bg, BackgroundColor_, [this] { emit backgroundChanged (); });
274  }
275 
276  QColor PlotItem::GetTextColor () const
277  {
278  return TextColor_;
279  }
280 
281  void PlotItem::SetTextColor (const QColor& color)
282  {
283  SetNewValue (color, TextColor_, [this] { emit textColorChanged (); });
284  }
285 
287  {
288  return GridLinesColor_;
289  }
290 
291  void PlotItem::SetGridLinesColor (const QColor& color)
292  {
293  SetNewValue (color, GridLinesColor_, [this] { emit gridLinesColorChanged (); });
294  }
295 
296  int PlotItem::GetXExtent () const
297  {
298  return XExtent_;
299  }
300 
301  int PlotItem::GetYExtent () const
302  {
303  return YExtent_;
304  }
305 
306  void PlotItem::paint (QPainter *painter)
307  {
308  const auto& rect = contentsBoundingRect ().toRect ();
309 
310  if (!Plot_)
311  {
312  Plot_ = std::make_shared<QwtPlot> ();
313  Plot_->setFrameShape (QFrame::NoFrame);
314  Plot_->setFrameShadow (QFrame::Plain);
315  Plot_->setLineWidth (0);
316  Plot_->setMidLineWidth (0);
317 
318  if (const auto canvas = qobject_cast<QwtPlotCanvas*> (Plot_->canvas ()))
319  canvas->setBorderRadius (0);
320  }
321 
322  auto& plot = *Plot_;
323  plot.enableAxis (QwtPlot::yLeft, LeftAxisEnabled_);
324  plot.enableAxis (QwtPlot::xBottom, BottomAxisEnabled_);
325  plot.setAxisTitle (QwtPlot::yLeft, LeftAxisTitle_);
326  plot.setAxisTitle (QwtPlot::xBottom, BottomAxisTitle_);
327 
328  if (plot.size () != rect.size ())
329  plot.resize (rect.size ());
330 
331  auto setPaletteColor = [&plot] (const QColor& color, QPalette::ColorRole role)
332  {
333  if (!color.isValid ())
334  return;
335 
336  auto pal = plot.palette ();
337  pal.setColor (role, { color });
338  plot.setPalette (pal);
339  };
340 
341  setPaletteColor (BackgroundColor_, QPalette::Window);
342  setPaletteColor (TextColor_, QPalette::WindowText);
343  setPaletteColor (TextColor_, QPalette::Text);
344 
345  if (!PlotTitle_.isEmpty ())
346  plot.setTitle (QwtText { PlotTitle_ });
347 
348  if (MinYValue_ < MaxYValue_)
349  {
350  plot.setAxisAutoScale (QwtPlot::yLeft, false);
351  plot.setAxisScale (QwtPlot::yLeft, MinYValue_, MaxYValue_);
352  }
353  plot.setAutoFillBackground (false);
354  plot.setCanvasBackground (Qt::transparent);
355 
356  if (YGridEnabled_)
357  {
358  auto grid = new QwtPlotGrid;
359  grid->enableYMin (YMinorGridEnabled_);
360  grid->enableX (false);
361  grid->setMajorPen (QPen (GridLinesColor_, 1, Qt::SolidLine));
362  grid->setMinorPen (QPen (GridLinesColor_, 1, Qt::DashLine));
363  grid->attach (&plot);
364  }
365 
366  auto items = Multipoints_;
367  if (items.isEmpty ())
368  items.push_back ({ Color_, {}, Points_ });
369 
370  if (MinXValue_ < MaxXValue_)
371  plot.setAxisScale (QwtPlot::xBottom, MinXValue_, MaxXValue_);
372  else if (const auto ptsCount = items.first ().Points_.size ())
373  plot.setAxisScale (QwtPlot::xBottom, 0, ptsCount - 1);
374 
375  std::vector<std::unique_ptr<QwtPlotCurve>> curves;
376  for (const auto& item : items)
377  {
378  curves.emplace_back (new QwtPlotCurve);
379  const auto curve = curves.back ().get ();
380 
381  curve->setPen (QPen (item.Color_));
382 
383  if (item.BrushColor_)
384  curve->setBrush (*item.BrushColor_);
385  else
386  {
387  auto brushColor = item.Color_;
388  brushColor.setAlphaF (Alpha_);
389  curve->setBrush (brushColor);
390  }
391 
392  curve->setRenderHint (QwtPlotItem::RenderAntialiased);
393  curve->attach (&plot);
394 
395  curve->setSamples (item.Points_.toVector ());
396  }
397 
398  plot.replot ();
399 
400  QwtPlotRenderer {}.render (&plot, painter, rect);
401 
402  const auto xExtent = CalcXExtent (plot);
403  const auto yExtent = CalcYExtent (plot);
404  if (xExtent != XExtent_ || yExtent != YExtent_)
405  {
406  XExtent_ = xExtent;
407  YExtent_ = yExtent;
408  emit extentsChanged ();
409  }
410  }
411 
412  template<typename T>
413  void PlotItem::SetNewValue (T val, T& ourVal, const std::function<void ()>& notifier)
414  {
415  if (val == ourVal)
416  return;
417 
418  ourVal = val;
419  notifier ();
420  update ();
421  }
422 
423  int PlotItem::CalcXExtent (QwtPlot& plot) const
424  {
425  int result = 0;
426  if (LeftAxisEnabled_)
427  result += plot.axisScaleDraw (QwtPlot::yLeft)->
428  extent (plot.axisFont (QwtPlot::yLeft));
429  return result;
430  }
431 
432  int PlotItem::CalcYExtent (QwtPlot& plot) const
433  {
434  int result = 0;
435  if (BottomAxisEnabled_)
436  result += plot.axisScaleDraw (QwtPlot::xBottom)->
437  extent (plot.axisFont (QwtPlot::xBottom));
438  if (!PlotTitle_.isEmpty ())
439  result += plot.titleLabel ()->sizeHint ().height ();
440  return result;
441  }
442 }
443 }
void SetMinXValue(double)
Definition: plotitem.cpp:140
QString GetLeftAxisTitle() const
Definition: plotitem.cpp:236
bool GetYGridEnabled() const
Definition: plotitem.cpp:175
double GetMaxYValue() const
Definition: plotitem.cpp:165
void paint(QPainter *) override
Definition: plotitem.cpp:306
QColor GetGridLinesColor() const
Definition: plotitem.cpp:286
QString GetBottomAxisTitle() const
Definition: plotitem.cpp:246
QColor GetTextColor() const
Definition: plotitem.cpp:276
void SetLeftAxisEnabled(bool)
Definition: plotitem.cpp:221
void gridLinesColorChanged()
QList< QPointF > GetPoints() const
Definition: plotitem.cpp:58
QColor GetColor() const
Definition: plotitem.cpp:206
double GetMaxXValue() const
Definition: plotitem.cpp:145
QVariant GetMultipoints() const
Definition: plotitem.cpp:73
double GetMinYValue() const
Definition: plotitem.cpp:155
void SetMaxXValue(double)
Definition: plotitem.cpp:150
void SetMultipoints(const QVariant &)
Definition: plotitem.cpp:92
void bottomAxisTitleChanged()
QColor GetBackground() const
Definition: plotitem.cpp:266
void SetMaxYValue(double)
Definition: plotitem.cpp:170
QString GetPlotTitle() const
Definition: plotitem.cpp:256
bool GetLeftAxisEnabled() const
Definition: plotitem.cpp:216
void SetPlotTitle(const QString &)
Definition: plotitem.cpp:261
void SetBackground(const QColor &)
Definition: plotitem.cpp:271
void SetTextColor(const QColor &)
Definition: plotitem.cpp:281
void SetMinYValue(double)
Definition: plotitem.cpp:160
int GetYExtent() const
Definition: plotitem.cpp:301
void bottomAxisEnabledChanged()
Q_DECLARE_METATYPE(QVariantList *)
void leftAxisTitleChanged()
void SetLeftAxisTitle(const QString &)
Definition: plotitem.cpp:241
double GetMinXValue() const
Definition: plotitem.cpp:135
unsigned long Window
Definition: xwrapper.h:44
int GetXExtent() const
Definition: plotitem.cpp:296
bool GetYMinorGridEnabled() const
Definition: plotitem.cpp:185
void SetGridLinesColor(const QColor &)
Definition: plotitem.cpp:291
void SetBottomAxisEnabled(bool)
Definition: plotitem.cpp:231
void SetPoints(const QList< QPointF > &)
Definition: plotitem.cpp:63
void SetYMinorGridEnabled(bool)
Definition: plotitem.cpp:190
void SetBottomAxisTitle(const QString &)
Definition: plotitem.cpp:251
void leftAxisEnabledChanged()
Definition: constants.h:35
void SetColor(const QColor &)
Definition: plotitem.cpp:211
double GetAlpha() const
Definition: plotitem.cpp:195
void SetAlpha(double)
Definition: plotitem.cpp:200
PlotItem(QQuickItem *=0)
Definition: plotitem.cpp:51
void SetYGridEnabled(bool)
Definition: plotitem.cpp:180
bool GetBottomAxisEnabled() const
Definition: plotitem.cpp:226