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