Add graph to stats page; update Rules
[harbour-pedalo.git] / src / graph.cpp
diff --git a/src/graph.cpp b/src/graph.cpp
new file mode 100644 (file)
index 0000000..338ab5e
--- /dev/null
@@ -0,0 +1,267 @@
+#include <QBrush>
+#include <QPainter>
+
+#include "journey.h"
+#include "graph.h"
+
+Graph::Graph(QQuickItem *parent)
+    : QQuickPaintedItem(parent)
+    , primary(QColor("#ff0000"))
+    , secondary(QColor("#00ff00"))
+    , highlight(QColor("#0000ff"))
+    , axisThickness(0.02)
+    , bars(7)
+    , gap(0.1)
+    , minmodel(0.0f)
+    , maxmodel(1.0f)
+    , miny(0.0f)
+    , maxy(1.0f)
+    , stepy(0.1f)
+    , unitsy("%")
+    , fontsize(24.0)
+    , animate(1.0)
+{
+    model.clear();
+    labelsx.clear();
+    labelsy.clear();
+}
+
+void Graph::paint(QPainter *painter) {
+    QLocale locale;
+    float barwidth;
+    float axiswidth;
+    int count;
+    int barfullwidth;
+    float labelygap;
+    float labelxgap;
+    int labels;
+    float labelheight;
+
+    QRectF size = contentsBoundingRect();
+
+    bars = model.length();
+    labelygap = size.height() * 0.1l;
+    labelxgap = size.width() * 0.11;
+    axiswidth = qMin(size.width() * axisThickness, size.height() * axisThickness);
+    barfullwidth = ((size.width() - labelxgap - axiswidth) / bars);
+    barwidth = barfullwidth * (1.0 - gap);
+    labels = labelsy.length() > 0 ? labelsy.length() : 1 + (maxy - miny) / stepy;
+    labelheight = (size.height() - labelygap - axiswidth) / (labels - 0.5);
+
+    QBrush axiscolour(primary);
+    QBrush barcolour(secondary);
+
+    painter->setBrush(axiscolour);
+    painter->setPen(Qt::NoPen);
+    painter->setRenderHint(QPainter::Antialiasing);
+    painter->setOpacity(1.0);
+
+    const QPointF points[6] = {
+        QPointF(labelxgap, (labelheight / 2.0)),
+        QPointF(labelxgap, size.height() - labelygap),
+        QPointF(size.width(), size.height() - labelygap),
+        QPointF(size.width(), size.height() - labelygap - axiswidth),
+        QPointF(labelxgap + axiswidth, size.height() - labelygap - axiswidth),
+        QPointF(labelxgap + axiswidth, (labelheight / 2.0))
+    };
+    painter->drawPolygon(points, 6);
+
+    if (bars > 0) {
+        painter->setBrush(barcolour);
+
+        count = 0;
+        for (QList<float>::const_iterator iter = model.constBegin(); (count < bars) && (iter != model.constEnd()); iter++) {
+            float barheight = ((*iter) - miny) / (maxy - miny);
+            barheight = qBound(0.0f, barheight, 1.0f) * (size.height() - labelygap - axiswidth - (labelheight / 2.0));
+            barheight *= animate;
+            painter->drawRect(labelxgap + axiswidth + (barfullwidth * count) + (barfullwidth * gap / 2.0), size.height() - labelygap - barheight - axiswidth, barwidth, barheight);
+
+            count++;
+        }
+    }
+
+    QFont font = painter->font();
+    font.setPixelSize(fontsize);
+    painter->setFont(font);
+    painter->setPen(primary);
+    painter->setBrush(Qt::NoBrush);
+
+    if ((bars > 0) && (labelsx.length() == bars)) {
+        for (count = 0; count < bars; count++) {
+            QRectF rect(labelxgap + axiswidth + (barfullwidth * count), size.height() - labelygap + 8.0, barfullwidth, labelygap - 8.0);
+            painter->drawText(rect, Qt::AlignHCenter | Qt::NoClip | Qt::TextSingleLine, labelsx[count]);
+            //painter->drawRect(rect);
+        }
+    }
+
+    if (labelsy.length() > 0) {
+        for (count = 0; count < labels; count++) {
+            QRectF rect(0, size.height() - (labelheight * (count + 0.5)) - labelygap, labelxgap - 8.0, labelheight);
+            painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight | Qt::NoClip | Qt::TextSingleLine, labelsy[count]);
+            //painter->drawRect(rect);
+        }
+    }
+    else {
+        float labelvalue = miny;
+        for (count = 0; count < labels; count++) {
+            QString labeltext = unitsy == "%" ? locale.toString(labelvalue * 100, 'f', 0) + "%" : locale.toString(labelvalue, 'g', 2) + unitsy;
+            QRectF rect(0, size.height() - (labelheight * (count + 0.5)) - labelygap, labelxgap - 8.0, labelheight);
+            painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight | Qt::NoClip | Qt::TextSingleLine, labeltext);
+            //painter->drawRect(rect);
+            labelvalue += stepy;
+        }
+
+    }
+}
+
+QList<float> Graph::getModel() const {
+    return model;
+}
+
+void Graph::setModel(QList<float> value) {
+    model = value;
+    emit modelChanged();
+
+    if (model.length() > 0) {
+        minmodel = model[0];
+        maxmodel = minmodel;
+        foreach (int y, model) {
+            if (y < minmodel) {
+                minmodel = y;
+            }
+            if (y > maxmodel) {
+                maxmodel = y;
+            }
+        }
+    }
+}
+
+QStringList Graph::getLabelsx() const {
+    return labelsx;
+}
+
+void Graph::setLabelsx(QStringList value) {
+    labelsx = value;
+    emit labelsxChanged();
+}
+
+QStringList Graph::getLabelsy() const {
+    return labelsy;
+}
+
+void Graph::setLabelsy(QStringList value) {
+    labelsy = value;
+    emit labelsyChanged();
+}
+
+QColor Graph::getPrimary() const {
+    return this->primary;
+}
+
+void Graph::setPrimary(QColor value) {
+    if (primary != value) {
+        primary = value;
+        emit primaryChanged(value);
+    }
+}
+
+QColor Graph::getSecondary() const {
+    return this->secondary;
+}
+
+void Graph::setSecondary(QColor value) {
+    if (secondary != value) {
+        secondary = value;
+        emit secondaryChanged(value);
+    }
+}
+
+QColor Graph::getHighlight() const {
+    return this->highlight;
+}
+
+void Graph::setHighlight(QColor value) {
+    if (highlight != value) {
+        highlight = value;
+        emit highlightChanged(value);
+    }
+}
+
+float Graph::getGap() const {
+    return gap;
+}
+
+void Graph::setGap(float value) {
+    if (gap != value) {
+        gap = value;
+        emit gapChanged(value);
+    }
+}
+
+float Graph::getMiny() const {
+    return miny;
+}
+
+void Graph::setMiny(float value) {
+    if (miny != value) {
+        miny = value;
+        emit minyChanged(value);
+    }
+}
+
+float Graph::getMaxy() const {
+    return maxy;
+}
+
+void Graph::setMaxy(float value) {
+    if (maxy != value) {
+        maxy = value;
+        emit maxyChanged(value);
+    }
+}
+
+float Graph::getStepy() const {
+    return stepy;
+}
+
+void Graph::setStepy(float value) {
+    if (stepy != value) {
+        stepy = value;
+        emit stepyChanged(value);
+    }
+}
+
+QString Graph::getUnitsy() const {
+    return unitsy;
+}
+
+void Graph::setUnitsy(QString value) {
+    if (unitsy != value) {
+        unitsy = value;
+        emit unitsyChanged();
+    }
+}
+
+float Graph::getFontsize() const {
+    return fontsize;
+}
+
+void Graph::setFontsize(float value) {
+    if (fontsize != value) {
+        fontsize = value;
+        emit fontsizeChanged(value);
+    }
+}
+
+float Graph::getAnimate() const {
+    return animate;
+}
+
+void Graph::setAnimate(float value) {
+    if (animate != value) {
+        animate = value;
+        emit animateChanged(value);
+        update();
+    }
+}
+