diff --git a/src/barchart/barchart.pri b/src/barchart/barchart.pri index 6b9594d..35668e6 100644 --- a/src/barchart/barchart.pri +++ b/src/barchart/barchart.pri @@ -14,7 +14,8 @@ SOURCES += \ $$PWD/qpercentbarchartseries.cpp \ $$PWD/qstackedbarchartseries.cpp \ $$PWD/separator.cpp \ - $$PWD/stackedbarpresenter.cpp + $$PWD/stackedbarpresenter.cpp \ + $$PWD/barvalue.cpp PRIVATE_HEADERS += \ $$PWD/bar_p.h \ @@ -24,12 +25,14 @@ PRIVATE_HEADERS += \ $$PWD/barpresenterbase.h \ $$PWD/percentbarpresenter.h \ $$PWD/separator_p.h \ - $$PWD/stackedbarpresenter.h - + $$PWD/stackedbarpresenter.h \ + $$PWD/barvalue_p.h + PUBLIC_HEADERS += \ $$PWD/qbarcategory.h \ $$PWD/qbarchartseries.h \ $$PWD/qbarset.h \ $$PWD/qpercentbarchartseries.h \ $$PWD/qstackedbarchartseries.h - \ No newline at end of file + + diff --git a/src/barchart/barchartmodel.cpp b/src/barchart/barchartmodel.cpp index 97a661e..55826af 100644 --- a/src/barchart/barchartmodel.cpp +++ b/src/barchart/barchartmodel.cpp @@ -134,14 +134,34 @@ qreal BarChartModel::valueAt(int set, int category) return mDataModel.at(set)->valueAt(category); } -qreal BarChartModel::categorySum(int column) +qreal BarChartModel::percentageAt(int set, int category) +{ + if ((set < 0) || (set >= mDataModel.count())) { + // No set, no value. + return 0; + } else if ((category < 0) || (category >= mDataModel.at(set)->count())) { + // No category, no value. + return 0; + } + + qreal value = mDataModel.at(set)->valueAt(category); + qreal total = categorySum(category); + if (0 == total) { + return 100.0; + } + + return value / total; +} + + +qreal BarChartModel::categorySum(int category) { qreal sum(0); - int count = mDataModel.count(); // Count rows + int count = mDataModel.count(); // Count sets - for (int row = 0; row < count; row++) { - if (column < mDataModel.at(row)->count()) { - sum += mDataModel.at(row)->valueAt(column); + for (int set = 0; set < count; set++) { + if (category < mDataModel.at(set)->count()) { + sum += mDataModel.at(set)->valueAt(category); } } return sum; diff --git a/src/barchart/barchartmodel_p.h b/src/barchart/barchartmodel_p.h index f19ad08..26f3009 100644 --- a/src/barchart/barchartmodel_p.h +++ b/src/barchart/barchartmodel_p.h @@ -33,8 +33,9 @@ public: qreal max(); // Maximum value of all sets qreal min(); // Minimum value of all sets qreal valueAt(int set, int category); + qreal percentageAt(int set, int category); - qreal categorySum(int column); + qreal categorySum(int category); qreal maxCategorySum(); // returns maximum sum of sets in all categories. QString label(int category); diff --git a/src/barchart/barpresenter.cpp b/src/barchart/barpresenter.cpp index d66b7d9..3323d2a 100644 --- a/src/barchart/barpresenter.cpp +++ b/src/barchart/barpresenter.cpp @@ -1,6 +1,7 @@ #include "barpresenter.h" #include "bar_p.h" #include "barlabel_p.h" +#include "barvalue_p.h" #include "qbarset.h" #include @@ -9,7 +10,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE BarPresenter::BarPresenter(BarChartModel& model, QGraphicsItem *parent) : BarPresenterBase(model,parent) { - mBarDefaultWidth = 5; + mBarDefaultWidth = 15; } void BarPresenter::layoutChanged() @@ -28,25 +29,25 @@ void BarPresenter::layoutChanged() // TODO: better way to auto-layout? // Use reals for accurancy (we might get some compiler warnings... :) - int itemCount = mModel.countCategories(); + int categoryCount = mModel.countCategories(); int setCount = mModel.countSets(); qreal tW = mWidth; qreal tH = mHeight; qreal tM = mModel.max(); qreal scale = (tH/tM); - qreal tC = itemCount+1; + qreal tC = categoryCount+1; qreal xStepPerSet = (tW/tC); // Scaling. int itemIndex(0); int labelIndex(0); - for (int item=0; item < itemCount; item++) { - qreal xPos = xStepPerSet * item + ((tW + mBarDefaultWidth*setCount)/(itemCount*2)); + for (int category=0; category < categoryCount; category++) { + qreal xPos = xStepPerSet * category + ((tW + mBarDefaultWidth*setCount)/(categoryCount*2)); qreal yPos = mHeight; for (int set = 0; set < setCount; set++) { - qreal barHeight = mModel.valueAt(set, item) * scale; + qreal barHeight = mModel.valueAt(set, category) * scale; Bar* bar = mBars.at(itemIndex); // TODO: width settable per bar? @@ -58,12 +59,33 @@ void BarPresenter::layoutChanged() } // TODO: Layout for labels, remove magic number - xPos = xStepPerSet * item + ((tW + mBarDefaultWidth*setCount)/(itemCount*2)); + xPos = xStepPerSet * category + ((tW + mBarDefaultWidth*setCount)/(categoryCount*2)); BarLabel* label = mLabels.at(labelIndex); label->setPos(xPos, mHeight + 20); labelIndex++; } + // Position floating values + itemIndex = 0; + for (int category=0; category < mModel.countCategories(); category++) { + qreal xPos = xStepPerSet * category + ((tW + mBarDefaultWidth*setCount)/(categoryCount*2)); + qreal yPos = mHeight; + for (int set=0; set < mModel.countSets(); set++) { + qreal barHeight = mModel.valueAt(set,category) * scale; + BarValue* value = mFloatingValues.at(itemIndex); + + // TODO: remove hard coding, apply layout + value->resize(100,50); + value->setPos(xPos + mBarDefaultWidth/2, yPos-barHeight/2); + value->setPen(QPen(QColor(255,255,255,255))); + + QString vString(QString::number(mModel.valueAt(set,category))); + value->setValueString(vString); + + itemIndex++; + xPos += mBarDefaultWidth; + } + } mLayoutDirty = true; } diff --git a/src/barchart/barpresenterbase.cpp b/src/barchart/barpresenterbase.cpp index 06c7328..b6d59f8 100644 --- a/src/barchart/barpresenterbase.cpp +++ b/src/barchart/barpresenterbase.cpp @@ -1,5 +1,6 @@ #include "barpresenterbase.h" #include "bar_p.h" +#include "barvalue_p.h" #include "barlabel_p.h" #include "separator_p.h" #include "qbarset.h" @@ -12,7 +13,7 @@ BarPresenterBase::BarPresenterBase(BarChartModel& model, QGraphicsItem *parent) ,mBarDefaultWidth(20) // TODO: remove hard coding, when we have layout code ready ,mLayoutSet(false) ,mLayoutDirty(true) - ,mSeparatorsVisible(true) + ,mSeparatorsVisible(false) ,mModel(model) { dataChanged(); @@ -59,6 +60,7 @@ void BarPresenterBase::dataChanged() mBars.clear(); mLabels.clear(); mSeparators.clear(); + mFloatingValues.clear(); // Create new graphic items for bars for (int s=0; s mBars; QList mLabels; QList mSeparators; + QList mFloatingValues; QPen mPen; }; diff --git a/src/barchart/barvalue.cpp b/src/barchart/barvalue.cpp new file mode 100644 index 0000000..7faaefd --- /dev/null +++ b/src/barchart/barvalue.cpp @@ -0,0 +1,58 @@ +#include "barvalue_p.h" +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +BarValue::BarValue(QGraphicsItem *parent) + : QGraphicsItem(parent) +{ +// setVisible(false); +} + +void BarValue::setValueString(QString str) +{ + mValueString = str; +} + +QString BarValue::valueString() +{ + return mValueString; +} + +void BarValue::setPen(const QPen& pen) +{ + mPen = pen; +} + +const QPen& BarValue::pen() +{ + return mPen; +} + +void BarValue::resize(qreal w, qreal h) +{ + mWidth = w; + mHeight = h; +} + +void BarValue::setPos(qreal x, qreal y) +{ + mXpos = x; + mYpos = y; +} + +void BarValue::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + painter->setPen(mPen); + painter->drawText(boundingRect(),mValueString); +} + +QRectF BarValue::boundingRect() const +{ + QRectF r(mXpos, mYpos, mXpos + mWidth, mYpos + mHeight); + return r; +} + + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/barchart/barvalue_p.h b/src/barchart/barvalue_p.h new file mode 100644 index 0000000..60f442c --- /dev/null +++ b/src/barchart/barvalue_p.h @@ -0,0 +1,45 @@ +#ifndef BARVALUE_P_H +#define BARVALUE_P_H + +#include "qchartglobal.h" +#include +#include + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + + +// Visual class for floating bar values +// TODO: fonts, colors etc. +// By default these are not visible. +class BarValue : public QGraphicsItem +{ +public: + BarValue(QGraphicsItem *parent = 0); + + void setValueString(QString str); + QString valueString(); + + void setPen(const QPen& pen); + const QPen& pen(); + + void resize(qreal w, qreal h); + void setPos(qreal x, qreal y); + + // From QGraphicsItem + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QRectF boundingRect() const; + +private: + + QPen mPen; + QString mValueString; + + qreal mXpos; + qreal mYpos; + qreal mWidth; + qreal mHeight; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // BARVALUE_P_H diff --git a/src/barchart/percentbarpresenter.cpp b/src/barchart/percentbarpresenter.cpp index 049644d..dd90d73 100644 --- a/src/barchart/percentbarpresenter.cpp +++ b/src/barchart/percentbarpresenter.cpp @@ -1,6 +1,7 @@ #include "percentbarpresenter.h" #include "bar_p.h" #include "barlabel_p.h" +#include "barvalue_p.h" #include "separator_p.h" #include "qbarset.h" #include @@ -37,10 +38,10 @@ void PercentBarPresenter::layoutChanged() qreal tC = count+1; qreal xStep = (tW/tC); qreal xPos = ((tW/tC) - mBarDefaultWidth / 2); + qreal h = mHeight; for (int category = 0; category < mModel.countCategories(); category++) { qreal colSum = mModel.categorySum(category); - qreal h = mHeight; qreal scale = (h / colSum); qreal yPos = h; for (int set=0; set < mModel.countSets(); set++) { @@ -63,14 +64,37 @@ void PercentBarPresenter::layoutChanged() } // Position separators - int separatorIndex(0); xPos = xStep + xStep/2; for (int s=0; s < mModel.countCategories() - 1; s++) { - Separator* sep = mSeparators.at(separatorIndex); + Separator* sep = mSeparators.at(s); sep->setPos(xPos,0); sep->setSize(QSizeF(1,mHeight)); xPos += xStep; - separatorIndex++; + } + + // Position floating values + itemIndex = 0; + xPos = ((tW/tC) - mBarDefaultWidth / 2); + for (int category=0; category < mModel.countCategories(); category++) { + qreal yPos = h; + qreal colSum = mModel.categorySum(category); + qreal scale = (h / colSum); + for (int set=0; set < mModel.countSets(); set++) { + qreal barHeight = mModel.valueAt(set,category) * scale; + BarValue* value = mFloatingValues.at(itemIndex); + + // TODO: remove hard coding, apply layout + value->setPos(xPos + mBarDefaultWidth/2, yPos-barHeight/2); + value->setPen(QPen(QColor(255,255,255,255))); + + QString vString(QString::number(mModel.percentageAt(set,category) * 100)); + vString.append("%"); + value->setValueString(vString); + + itemIndex++; + yPos -= barHeight; + } + xPos += xStep; } mLayoutDirty = true; diff --git a/src/barchart/qbarset.cpp b/src/barchart/qbarset.cpp index eb6533f..bde3c8e 100644 --- a/src/barchart/qbarset.cpp +++ b/src/barchart/qbarset.cpp @@ -59,9 +59,10 @@ const QBrush& QBarSet::brush() const void QBarSet::barClicked() { + qDebug() << "QBarset::barClicked"; // Some bar of this set has been clicked // TODO: What happens then? - qDebug() << "bar Clicked"; + emit clicked(); // Notify that set has been clicked } diff --git a/src/barchart/qbarset.h b/src/barchart/qbarset.h index a071a74..9202c8b 100644 --- a/src/barchart/qbarset.h +++ b/src/barchart/qbarset.h @@ -27,7 +27,8 @@ public: void setBrush(const QBrush& brush); const QBrush& brush() const; -// void clicked(); +Q_SIGNALS: + void clicked(); /* void hoverEnter(); void hoverLeave(); diff --git a/src/barchart/stackedbarpresenter.cpp b/src/barchart/stackedbarpresenter.cpp index 4c73fb4..67c0c7b 100644 --- a/src/barchart/stackedbarpresenter.cpp +++ b/src/barchart/stackedbarpresenter.cpp @@ -1,6 +1,7 @@ #include "stackedbarpresenter.h" #include "bar_p.h" #include "barlabel_p.h" +#include "barvalue_p.h" #include "separator_p.h" #include "qbarset.h" #include @@ -68,14 +69,35 @@ void StackedBarPresenter::layoutChanged() } // Position separators - int separatorIndex(0); xPos = xStep + xStep/2; for (int s=0; s < mModel.countCategories() - 1; s++) { - Separator* sep = mSeparators.at(separatorIndex); + Separator* sep = mSeparators.at(s); sep->setPos(xPos,0); sep->setSize(QSizeF(1,mHeight)); xPos += xStep; - separatorIndex++; + } + + // Position floating values + itemIndex = 0; + xPos = ((tW/tC) - mBarDefaultWidth / 2); + for (int category=0; category < mModel.countCategories(); category++) { + qreal yPos = h; + for (int set=0; set < mModel.countSets(); set++) { + qreal barHeight = mModel.valueAt(set,category) * scale; + BarValue* value = mFloatingValues.at(itemIndex); + + // TODO: remove hard coding, apply layout + value->resize(100,50); + value->setPos(xPos + mBarDefaultWidth/2, yPos-barHeight/2); + value->setPen(QPen(QColor(255,255,255,255))); + + QString vString(QString::number(mModel.valueAt(set,category))); + value->setValueString(vString); + + itemIndex++; + yPos -= barHeight; + } + xPos += xStep; } mLayoutDirty = true;