LeechCraft  0.6.70-6645-gcd10d7e
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 #include <util.h>
45 
47 
48 namespace LeechCraft
49 {
50 namespace Util
51 {
52 #if QT_VERSION < 0x050000
53  PlotItem::PlotItem (QDeclarativeItem *parent)
54  : QDeclarativeItem { parent }
55 #else
56  PlotItem::PlotItem (QQuickItem *parent)
57  : QQuickPaintedItem { parent }
58 #endif
59  , Color_ { "#FF4B10" }
60  {
61 #if QT_VERSION < 0x050000
62  setFlag (QGraphicsItem::ItemHasNoContents, false);
63 #else
64  setFlag (ItemHasContents, true);
65 #endif
66  }
67 
69  {
70  return Points_;
71  }
72 
74  {
75  if (pts == Points_)
76  return;
77 
78  Points_ = pts;
79  emit pointsChanged ();
80  update ();
81  }
82 
83  QVariant PlotItem::GetMultipoints () const
84  {
85  QVariantList result;
86  for (const auto& set : Multipoints_)
87  {
88  auto map = Util::MakeMap<QString, QVariant> ({
89  { "color", QVariant::fromValue (set.Color_) },
90  { "points", QVariant::fromValue (set.Points_) }
91  });
92 
93  if (set.BrushColor_)
94  map ["brushColor"] = *set.BrushColor_;
95 
96  result << map;
97  }
98  return result;
99  }
100 
101  void PlotItem::SetMultipoints (const QVariant& variant)
102  {
103  Multipoints_.clear ();
104 
105  for (const auto& set : variant.toList ())
106  {
107  const auto& map = set.toMap ();
108 
109  const auto& colorVar = map ["color"];
110  const auto& pointsVar = map ["points"];
111 
112  boost::optional<QColor> brushColor;
113  if (map.contains ("brushColor"))
114  {
115  const auto& brushVar = map ["brushColor"];
116  if (!brushVar.canConvert<QString> ())
117  qWarning () << Q_FUNC_INFO
118  << "invalid brush color"
119  << brushVar;
120  else
121  brushColor = QColor { brushVar.toString () };
122  }
123 
124  if (!colorVar.canConvert<QString> () ||
125  !pointsVar.canConvert<QList<QPointF>> ())
126  {
127  qWarning () << Q_FUNC_INFO
128  << "invalid map"
129  << map;
130  qWarning () << Q_FUNC_INFO
131  << "ignoring this point";
132  continue;
133  }
134 
135  Multipoints_.append ({
136  map ["color"].toString (),
137  brushColor,
138  map ["points"].value<QList<QPointF>> ()
139  });
140  }
141  update ();
142  }
143 
144  double PlotItem::GetMinXValue () const
145  {
146  return MinXValue_;
147  }
148 
149  void PlotItem::SetMinXValue (double val)
150  {
151  SetNewValue (val, MinXValue_, [this] { emit minXValueChanged (); });
152  }
153 
154  double PlotItem::GetMaxXValue () const
155  {
156  return MaxXValue_;
157  }
158 
159  void PlotItem::SetMaxXValue (double val)
160  {
161  SetNewValue (val, MaxXValue_, [this] { emit maxXValueChanged (); });
162  }
163 
164  double PlotItem::GetMinYValue () const
165  {
166  return MinYValue_;
167  }
168 
169  void PlotItem::SetMinYValue (double val)
170  {
171  SetNewValue (val, MinYValue_, [this] { emit minYValueChanged (); });
172  }
173 
174  double PlotItem::GetMaxYValue () const
175  {
176  return MaxYValue_;
177  }
178 
179  void PlotItem::SetMaxYValue (double val)
180  {
181  SetNewValue (val, MaxYValue_, [this] { emit maxYValueChanged (); });
182  }
183 
185  {
186  return YGridEnabled_;
187  }
188 
190  {
191  SetNewValue (val, YGridEnabled_, [this] { emit yGridChanged (); });
192  }
193 
195  {
196  return YMinorGridEnabled_;
197  }
198 
200  {
201  SetNewValue (val, YMinorGridEnabled_, [this] { emit yMinorGridChanged (); });
202  }
203 
204  double PlotItem::GetAlpha () const
205  {
206  return Alpha_;
207  }
208 
209  void PlotItem::SetAlpha (double a)
210  {
211  Alpha_ = a;
212  emit alphaChanged ();
213  }
214 
215  QColor PlotItem::GetColor () const
216  {
217  return Color_;
218  }
219 
220  void PlotItem::SetColor (const QColor& color)
221  {
222  SetNewValue (color, Color_, [this] { emit colorChanged (); });
223  }
224 
226  {
227  return LeftAxisEnabled_;
228  }
229 
230  void PlotItem::SetLeftAxisEnabled (bool enabled)
231  {
232  SetNewValue (enabled, LeftAxisEnabled_, [this] { emit leftAxisEnabledChanged (); });
233  }
234 
236  {
237  return BottomAxisEnabled_;
238  }
239 
240  void PlotItem::SetBottomAxisEnabled (bool enabled)
241  {
242  SetNewValue (enabled, BottomAxisEnabled_, [this] { emit bottomAxisEnabledChanged (); });
243  }
244 
245  QString PlotItem::GetLeftAxisTitle () const
246  {
247  return LeftAxisTitle_;
248  }
249 
250  void PlotItem::SetLeftAxisTitle (const QString& title)
251  {
252  SetNewValue (title, LeftAxisTitle_, [this] { emit leftAxisTitleChanged (); });
253  }
254 
256  {
257  return BottomAxisTitle_;
258  }
259 
260  void PlotItem::SetBottomAxisTitle (const QString& title)
261  {
262  SetNewValue (title, BottomAxisTitle_, [this] { emit bottomAxisTitleChanged (); });
263  }
264 
265  QString PlotItem::GetPlotTitle () const
266  {
267  return PlotTitle_;
268  }
269 
270  void PlotItem::SetPlotTitle (const QString& title)
271  {
272  SetNewValue (title, PlotTitle_, [this] { emit plotTitleChanged (); });
273  }
274 
275  QColor PlotItem::GetBackground () const
276  {
277  return BackgroundColor_;
278  }
279 
280  void PlotItem::SetBackground (const QColor& bg)
281  {
282  SetNewValue (bg, BackgroundColor_, [this] { emit backgroundChanged (); });
283  }
284 
285  QColor PlotItem::GetTextColor () const
286  {
287  return TextColor_;
288  }
289 
290  void PlotItem::SetTextColor (const QColor& color)
291  {
292  SetNewValue (color, TextColor_, [this] { emit textColorChanged (); });
293  }
294 
296  {
297  return GridLinesColor_;
298  }
299 
300  void PlotItem::SetGridLinesColor (const QColor& color)
301  {
302  SetNewValue (color, GridLinesColor_, [this] { emit gridLinesColorChanged (); });
303  }
304 
305  int PlotItem::GetXExtent () const
306  {
307  return XExtent_;
308  }
309 
310  int PlotItem::GetYExtent () const
311  {
312  return YExtent_;
313  }
314 
315 #if QT_VERSION < 0x050000
316  void PlotItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*)
317  {
318  const auto& rect = option->rect;
319 #else
320  void PlotItem::paint (QPainter *painter)
321  {
322  const auto& rect = contentsBoundingRect ().toRect ();
323 #endif
324 
325  if (!Plot_)
326  {
327  Plot_ = std::make_shared<QwtPlot> ();
328  Plot_->setFrameShape (QFrame::NoFrame);
329  Plot_->setFrameShadow (QFrame::Plain);
330  Plot_->setLineWidth (0);
331  Plot_->setMidLineWidth (0);
332 
333  if (const auto canvas = qobject_cast<QwtPlotCanvas*> (Plot_->canvas ()))
334  canvas->setBorderRadius (0);
335  }
336 
337  auto& plot = *Plot_;
338  plot.enableAxis (QwtPlot::yLeft, LeftAxisEnabled_);
339  plot.enableAxis (QwtPlot::xBottom, BottomAxisEnabled_);
340  plot.setAxisTitle (QwtPlot::yLeft, LeftAxisTitle_);
341  plot.setAxisTitle (QwtPlot::xBottom, BottomAxisTitle_);
342 
343  if (plot.size () != rect.size ())
344  plot.resize (rect.size ());
345 
346  auto setPaletteColor = [&plot] (const QColor& color, QPalette::ColorRole role)
347  {
348  if (!color.isValid ())
349  return;
350 
351  auto pal = plot.palette ();
352  pal.setColor (role, { color });
353  plot.setPalette (pal);
354  };
355 
356  setPaletteColor (BackgroundColor_, QPalette::Window);
357  setPaletteColor (TextColor_, QPalette::WindowText);
358  setPaletteColor (TextColor_, QPalette::Text);
359 
360  if (!PlotTitle_.isEmpty ())
361  plot.setTitle (QwtText { PlotTitle_ });
362 
363  if (MinYValue_ < MaxYValue_)
364  {
365  plot.setAxisAutoScale (QwtPlot::yLeft, false);
366  plot.setAxisScale (QwtPlot::yLeft, MinYValue_, MaxYValue_);
367  }
368  plot.setAutoFillBackground (false);
369  plot.setCanvasBackground (Qt::transparent);
370 
371  if (YGridEnabled_)
372  {
373  auto grid = new QwtPlotGrid;
374  grid->enableYMin (YMinorGridEnabled_);
375  grid->enableX (false);
376 #if QWT_VERSION >= 0x060100
377  grid->setMajorPen (QPen (GridLinesColor_, 1, Qt::SolidLine));
378  grid->setMinorPen (QPen (GridLinesColor_, 1, Qt::DashLine));
379 #else
380  grid->setMajPen (QPen (GridLinesColor_, 1, Qt::SolidLine));
381  grid->setMinPen (QPen (GridLinesColor_, 1, Qt::DashLine));
382 #endif
383  grid->attach (&plot);
384  }
385 
386  auto items = Multipoints_;
387  if (items.isEmpty ())
388  items.push_back ({ Color_, {}, Points_ });
389 
390  if (MinXValue_ < MaxXValue_)
391  plot.setAxisScale (QwtPlot::xBottom, MinXValue_, MaxXValue_);
392  else if (const auto ptsCount = items.first ().Points_.size ())
393  plot.setAxisScale (QwtPlot::xBottom, 0, ptsCount - 1);
394 
395  std::vector<std::unique_ptr<QwtPlotCurve>> curves;
396  for (const auto& item : items)
397  {
398  curves.emplace_back (new QwtPlotCurve);
399  const auto curve = curves.back ().get ();
400 
401  curve->setPen (QPen (item.Color_));
402 
403  if (item.BrushColor_)
404  curve->setBrush (*item.BrushColor_);
405  else
406  {
407  auto brushColor = item.Color_;
408  brushColor.setAlphaF (Alpha_);
409  curve->setBrush (brushColor);
410  }
411 
412  curve->setRenderHint (QwtPlotItem::RenderAntialiased);
413  curve->attach (&plot);
414 
415  curve->setSamples (item.Points_.toVector ());
416  }
417 
418  plot.replot ();
419 
420  QwtPlotRenderer {}.render (&plot, painter, rect);
421 
422  const auto xExtent = CalcXExtent (plot);
423  const auto yExtent = CalcYExtent (plot);
424  if (xExtent != XExtent_ || yExtent != YExtent_)
425  {
426  XExtent_ = xExtent;
427  YExtent_ = yExtent;
428  emit extentsChanged ();
429  }
430  }
431 
432  template<typename T>
433  void PlotItem::SetNewValue (T val, T& ourVal, const std::function<void ()>& notifier)
434  {
435  if (val == ourVal)
436  return;
437 
438  ourVal = val;
439  notifier ();
440  update ();
441  }
442 
443  int PlotItem::CalcXExtent (QwtPlot& plot) const
444  {
445  int result = 0;
446  if (LeftAxisEnabled_)
447  result += plot.axisScaleDraw (QwtPlot::yLeft)->
448  extent (plot.axisFont (QwtPlot::yLeft));
449  return result;
450  }
451 
452  int PlotItem::CalcYExtent (QwtPlot& plot) const
453  {
454  int result = 0;
455  if (BottomAxisEnabled_)
456  result += plot.axisScaleDraw (QwtPlot::xBottom)->
457  extent (plot.axisFont (QwtPlot::xBottom));
458  if (!PlotTitle_.isEmpty ())
459  result += plot.titleLabel ()->sizeHint ().height ();
460  return result;
461  }
462 }
463 }
QList< QPointF > GetPoints() const
Definition: plotitem.cpp:68
QColor GetTextColor() const
Definition: plotitem.cpp:285
double GetMinXValue() const
Definition: plotitem.cpp:144
double GetMaxXValue() const
Definition: plotitem.cpp:154
QString GetBottomAxisTitle() const
Definition: plotitem.cpp:255
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override
Definition: plotitem.cpp:316
bool GetLeftAxisEnabled() const
Definition: plotitem.cpp:225
void SetGridLinesColor(const QColor &)
Definition: plotitem.cpp:300
void SetBottomAxisTitle(const QString &)
Definition: plotitem.cpp:260
void SetLeftAxisTitle(const QString &)
Definition: plotitem.cpp:250
void SetPoints(const QList< QPointF > &)
Definition: plotitem.cpp:73
QColor GetColor() const
Definition: plotitem.cpp:215
void SetYMinorGridEnabled(bool)
Definition: plotitem.cpp:199
QString GetPlotTitle() const
Definition: plotitem.cpp:265
QString GetLeftAxisTitle() const
Definition: plotitem.cpp:245
void SetMultipoints(const QVariant &)
Definition: plotitem.cpp:101
bool GetBottomAxisEnabled() const
Definition: plotitem.cpp:235
bool GetYMinorGridEnabled() const
Definition: plotitem.cpp:194
double GetAlpha() const
Definition: plotitem.cpp:204
double GetMaxYValue() const
Definition: plotitem.cpp:174
double GetMinYValue() const
Definition: plotitem.cpp:164
QVariant GetMultipoints() const
Definition: plotitem.cpp:83
void SetColor(const QColor &)
Definition: plotitem.cpp:220
void SetBackground(const QColor &)
Definition: plotitem.cpp:280
unsigned long Window
Definition: xwrapper.h:50
bool GetYGridEnabled() const
Definition: plotitem.cpp:184
Q_DECLARE_METATYPE(LeechCraft::ANFieldData)
void SetPlotTitle(const QString &)
Definition: plotitem.cpp:270
QColor GetGridLinesColor() const
Definition: plotitem.cpp:295
QColor GetBackground() const
Definition: plotitem.cpp:275
PlotItem(QDeclarativeItem *=0)
Definition: plotitem.cpp:53
void SetBottomAxisEnabled(bool)
Definition: plotitem.cpp:240
void SetTextColor(const QColor &)
Definition: plotitem.cpp:290