diff --git a/src/Charts/GenericLegend.cpp b/src/Charts/GenericLegend.cpp index d55e70517..3271c71dd 100644 --- a/src/Charts/GenericLegend.cpp +++ b/src/Charts/GenericLegend.cpp @@ -161,6 +161,7 @@ GenericLegend::GenericLegend(Context *context, GenericPlot *plot) : context(cont layout = new QHBoxLayout(this); layout->addStretch(); + orientation=Qt::Horizontal; xname=""; clickable=true; @@ -184,6 +185,33 @@ GenericLegend::addSeries(QString name, QColor color) connect(add, SIGNAL(clicked(QString,bool)), this, SIGNAL(clicked(QString,bool))); } +void +GenericLegend::setOrientation(Qt::Orientation o) +{ + if (orientation == o) return; // already is. + + // set new orientation + orientation = o; + + QBoxLayout *newlayout; + if (orientation == Qt::Horizontal) newlayout = new QHBoxLayout(); + else newlayout = new QVBoxLayout(); + newlayout->addStretch(); + + // remove from layout and redo + QMapIterator i(items); + while (i.hasNext()) { + i.next(); + layout->removeWidget(i.value()); + newlayout->insertWidget(0, i.value()); + } + + // replace the layout + delete layout; + setLayout(newlayout); + layout = newlayout; + +} void GenericLegend::addX(QString name) { diff --git a/src/Charts/GenericLegend.h b/src/Charts/GenericLegend.h index 4f24d020a..63e6d28f3 100644 --- a/src/Charts/GenericLegend.h +++ b/src/Charts/GenericLegend.h @@ -95,20 +95,23 @@ class GenericLegend : public QWidget { void clicked(QString name, bool enabled); // someone clicked on a legend and enabled/disabled it public slots: + void setValue(QPointF value, QString name); void unhover(QString name); void unhoverx(); void setClickable(bool x); + void setOrientation(Qt::Orientation); private: // a label has a unique name, not directly tide to // a series or axis value, it depends... Context *context; GenericPlot *plot; - QHBoxLayout *layout; + QBoxLayout *layout; QMap items; QString xname; bool clickable; + Qt::Orientation orientation; }; #endif diff --git a/src/Charts/GenericPlot.cpp b/src/Charts/GenericPlot.cpp index 693643f0d..c81ad24d3 100644 --- a/src/Charts/GenericPlot.cpp +++ b/src/Charts/GenericPlot.cpp @@ -33,9 +33,10 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context) : QWidget(parent), c barseries=NULL; bottom=left=true; - QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(0); mainLayout->setContentsMargins(0,0,0,0); + leftLayout = new QHBoxLayout(); // setup the chart qchart = new QChart(); @@ -67,7 +68,9 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context) : QWidget(parent), c // add all widgets to the view mainLayout->addWidget(legend); - mainLayout->addWidget(chartview); + holder=mainLayout; + mainLayout->addLayout(leftLayout); + leftLayout->addWidget(chartview); // watch for colors changing connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32))); @@ -327,7 +330,7 @@ GenericPlot::plotAreaChanged() } bool -GenericPlot::initialiseChart(QString title, int type, bool animate) +GenericPlot::initialiseChart(QString title, int type, bool animate, int legpos) { // if we changed the type, all series must go if (charttype != type) { @@ -360,6 +363,31 @@ GenericPlot::initialiseChart(QString title, int type, bool animate) // by default they are disabled anyway qchart->setAnimationOptions(animate ? QChart::SeriesAnimations : QChart::NoAnimation); + // lets move the legend, only support top or bottom for now + holder->removeWidget(legend); + switch (legpos) { + case 0: // bottom + legend->setOrientation(Qt::Horizontal); + mainLayout->insertWidget(-1, legend); // at end + holder=mainLayout; + break; + case 1: // left + legend->setOrientation(Qt::Vertical); + leftLayout->insertWidget(0, legend); // at beginning + holder=leftLayout; + break; + case 2: // top + legend->setOrientation(Qt::Horizontal); + mainLayout->insertWidget(0, legend); // at front + holder=mainLayout; + break; + case 3: // right + legend->setOrientation(Qt::Vertical); + leftLayout->insertWidget(-1, legend); // at end + holder=leftLayout; + break; + } + // what kind of selector do we use? if (charttype==GC_CHART_LINE) selector->setMode(GenericSelectTool::XRANGE); else selector->setMode(GenericSelectTool::RECTANGLE); @@ -371,7 +399,7 @@ GenericPlot::initialiseChart(QString title, int type, bool animate) bool GenericPlot::addCurve(QString name, QVector xseries, QVector yseries, QString xname, QString yname, QStringList labels, QStringList colors, - int /*line TODO*/, int /*symbol TODO */, int size, QString color, int opacity, bool opengl) + int linestyle, int /*symbol TODO */, int size, QString color, int opacity, bool opengl) { // if curve already exists, remove it if (charttype==GC_CHART_LINE || charttype==GC_CHART_SCATTER || charttype==GC_CHART_PIE) { @@ -425,7 +453,7 @@ GenericPlot::addCurve(QString name, QVector xseries, QVector yse // aesthetics add->setBrush(Qt::NoBrush); QPen pen(color); - pen.setStyle(Qt::SolidLine); + pen.setStyle(static_cast(linestyle)); pen.setWidth(size); add->setPen(pen); add->setOpacity(double(opacity) / 100.0); // 0-100% to 0.0-1.0 values diff --git a/src/Charts/GenericPlot.h b/src/Charts/GenericPlot.h index cfd98351d..b638c9b4e 100644 --- a/src/Charts/GenericPlot.h +++ b/src/Charts/GenericPlot.h @@ -134,7 +134,7 @@ class GenericPlot : public QWidget { void configChanged(qint32); // set chart settings - bool initialiseChart(QString title, int type, bool animate); + bool initialiseChart(QString title, int type, bool animate, int legendpos); // add a curve, associating an axis bool addCurve(QString name, QVector xseries, QVector yseries, QString xname, QString yname, @@ -166,6 +166,9 @@ class GenericPlot : public QWidget { QChartView *chartview; GenericSelectTool *selector; QChart *qchart; + QVBoxLayout *mainLayout; + QBoxLayout *leftLayout; + QBoxLayout *holder; // who has me at the mo? // trap widget events and pass to event handler bool eventFilter(QObject *, QEvent *e); diff --git a/src/Charts/GenericSelectTool.cpp b/src/Charts/GenericSelectTool.cpp index 23ab34df1..18ac1fec1 100644 --- a/src/Charts/GenericSelectTool.cpp +++ b/src/Charts/GenericSelectTool.cpp @@ -274,7 +274,10 @@ void GenericSelectTool::paint(QPainter*painter, const QStyleOptionGraphicsItem * painter->drawText(maxxp-QPointF(0,4), label); label=QString("%1").arg(calc.x.min); painter->drawText(minxp-QPointF(0,4), label); - label=QString("%1").arg(calc.x.mean); + + // scatter sees mean, line/timeseries more likely to want dx + if (host->charttype == GC_CHART_SCATTER) label=QString("%1").arg(calc.x.mean); + else label=QString("%1").arg(calc.x.max - calc.x.min); painter->drawText(avgxp-QPointF(0,4), label); // @@ -329,6 +332,7 @@ GenericSelectTool::reset() hoverseries = NULL; hoverpoints.clear(); hoveraxis = NULL; + hidden.clear(); resetSelections(); rectchanged=true; update(); diff --git a/src/Charts/PythonChart.cpp b/src/Charts/PythonChart.cpp index abe32a295..9d238bca5 100644 --- a/src/Charts/PythonChart.cpp +++ b/src/Charts/PythonChart.cpp @@ -454,7 +454,7 @@ PythonChart::setWeb(bool x) renderlayout->insertWidget(0,plot); // signals to update it - connect(this, SIGNAL(emitChart(QString,int,bool)), plot, SLOT(initialiseChart(QString,int,bool))); + connect(this, SIGNAL(emitChart(QString,int,bool,int)), plot, SLOT(initialiseChart(QString,int,bool,int))); connect(this, SIGNAL(emitCurve(QString,QVector,QVector,QString,QString,QStringList,QStringList,int,int,int,QString,int,bool)), plot, SLOT( addCurve(QString,QVector,QVector,QString,QString,QStringList,QStringList,int,int,int,QString,int,bool))); connect(this, SIGNAL(emitAxis(QString,bool,int,double,double,int,QString,QString,bool,QStringList)), diff --git a/src/Charts/PythonChart.h b/src/Charts/PythonChart.h index de1904c99..e0e7b3811 100644 --- a/src/Charts/PythonChart.h +++ b/src/Charts/PythonChart.h @@ -141,7 +141,7 @@ class PythonChart : public GcChartWindow, public PythonHost { signals: void setUrl(QUrl); - void emitChart(QString title, int type, bool animate); + void emitChart(QString title, int type, bool animate, int legpos); void emitCurve(QString name, QVector xseries, QVector yseries, QString xname, QString yname, QStringList labels, QStringList colors, int line, int symbol, int size, QString color, int opacity, bool opengl); diff --git a/src/Python/SIP/Bindings.cpp b/src/Python/SIP/Bindings.cpp index 4583953fd..90a7dfb7c 100644 --- a/src/Python/SIP/Bindings.cpp +++ b/src/Python/SIP/Bindings.cpp @@ -58,9 +58,9 @@ Bindings::webpage(QString url) const } bool -Bindings::configChart(QString title, int type, bool animate) const +Bindings::configChart(QString title, int type, bool animate, int pos) const { - python->chart->emitChart(title, type, animate); + python->chart->emitChart(title, type, animate, pos); return true; } diff --git a/src/Python/SIP/Bindings.h b/src/Python/SIP/Bindings.h index 629381ee7..b0e01ddee 100644 --- a/src/Python/SIP/Bindings.h +++ b/src/Python/SIP/Bindings.h @@ -114,7 +114,7 @@ class Bindings { bool postProcess(QString processor, PyObject *activity = NULL) const; // working with charts - bool configChart(QString title, int type, bool animate) const; + bool configChart(QString title, int type, bool animate, int pos) const; bool setCurve(QString name, PyObject *xseries, PyObject *yseries, QString xname, QString yname, QStringList labels, QStringList colors, int line, int symbol, int symbolsize, QString color, int opacity, bool opengl) const; diff --git a/src/Python/SIP/goldencheetah.sip b/src/Python/SIP/goldencheetah.sip index 671ee8a82..dde7c73f3 100644 --- a/src/Python/SIP/goldencheetah.sip +++ b/src/Python/SIP/goldencheetah.sip @@ -388,7 +388,7 @@ public: bool postProcess(QString processor, PyObject *activity = NULL) const; // working with qt charts - bool configChart(QString title, int type, bool animate) const; + bool configChart(QString title, int type, bool animate, int legpos) const; bool setCurve(QString name, PyObject *xseries, PyObject *yseries, QString xname, QString yname, QStringList labels, QStringList colors, int line, int symbol, int symbolsize, QString color, int opacity, bool opengl) const; diff --git a/src/Python/SIP/sipAPIgoldencheetah.h b/src/Python/SIP/sipAPIgoldencheetah.h index 7b6ae58da..0d7527dfd 100644 --- a/src/Python/SIP/sipAPIgoldencheetah.h +++ b/src/Python/SIP/sipAPIgoldencheetah.h @@ -125,62 +125,64 @@ #define sipName_colors &sipStrings_goldencheetah[616] #define sipNameNr_labels 623 #define sipName_labels &sipStrings_goldencheetah[623] -#define sipNameNr_metric 630 -#define sipName_metric &sipStrings_goldencheetah[630] +#define sipNameNr_legpos 630 +#define sipName_legpos &sipStrings_goldencheetah[630] +#define sipNameNr_metric 637 +#define sipName_metric &sipStrings_goldencheetah[637] #define sipNameNr_series 515 #define sipName_series &sipStrings_goldencheetah[515] -#define sipNameNr_season 637 -#define sipName_season &sipStrings_goldencheetah[637] -#define sipNameNr_filter 644 -#define sipName_filter &sipStrings_goldencheetah[644] -#define sipNameNr_result 651 -#define sipName_result &sipStrings_goldencheetah[651] -#define sipNameNr_remove 658 -#define sipName_remove &sipStrings_goldencheetah[658] -#define sipNameNr_append 665 -#define sipName_append &sipStrings_goldencheetah[665] -#define sipNameNr_align 672 -#define sipName_align &sipStrings_goldencheetah[672] +#define sipNameNr_season 644 +#define sipName_season &sipStrings_goldencheetah[644] +#define sipNameNr_filter 651 +#define sipName_filter &sipStrings_goldencheetah[651] +#define sipNameNr_result 658 +#define sipName_result &sipStrings_goldencheetah[658] +#define sipNameNr_remove 665 +#define sipName_remove &sipStrings_goldencheetah[665] +#define sipNameNr_append 672 +#define sipName_append &sipStrings_goldencheetah[672] +#define sipNameNr_align 679 +#define sipName_align &sipStrings_goldencheetah[679] #define sipNameNr_color 361 #define sipName_color &sipStrings_goldencheetah[361] -#define sipNameNr_yname 678 -#define sipName_yname &sipStrings_goldencheetah[678] -#define sipNameNr_xname 684 -#define sipName_xname &sipStrings_goldencheetah[684] -#define sipNameNr_title 690 -#define sipName_title &sipStrings_goldencheetah[690] -#define sipNameNr_index 696 -#define sipName_index &sipStrings_goldencheetah[696] -#define sipNameNr_group 702 -#define sipName_group &sipStrings_goldencheetah[702] -#define sipNameNr_xdata 708 -#define sipName_xdata &sipStrings_goldencheetah[708] -#define sipNameNr_sport 714 -#define sipName_sport &sipStrings_goldencheetah[714] -#define sipNameNr_value 720 -#define sipName_value &sipStrings_goldencheetah[720] -#define sipNameNr_build 726 -#define sipName_build &sipStrings_goldencheetah[726] -#define sipNameNr_line 732 -#define sipName_line &sipStrings_goldencheetah[732] -#define sipNameNr_join 737 -#define sipName_join &sipStrings_goldencheetah[737] -#define sipNameNr_name 679 -#define sipName_name &sipStrings_goldencheetah[679] -#define sipNameNr_type 742 -#define sipName_type &sipStrings_goldencheetah[742] -#define sipNameNr_date 747 -#define sipName_date &sipStrings_goldencheetah[747] -#define sipNameNr_log 752 -#define sipName_log &sipStrings_goldencheetah[752] +#define sipNameNr_yname 685 +#define sipName_yname &sipStrings_goldencheetah[685] +#define sipNameNr_xname 691 +#define sipName_xname &sipStrings_goldencheetah[691] +#define sipNameNr_title 697 +#define sipName_title &sipStrings_goldencheetah[697] +#define sipNameNr_index 703 +#define sipName_index &sipStrings_goldencheetah[703] +#define sipNameNr_group 709 +#define sipName_group &sipStrings_goldencheetah[709] +#define sipNameNr_xdata 715 +#define sipName_xdata &sipStrings_goldencheetah[715] +#define sipNameNr_sport 721 +#define sipName_sport &sipStrings_goldencheetah[721] +#define sipNameNr_value 727 +#define sipName_value &sipStrings_goldencheetah[727] +#define sipNameNr_build 733 +#define sipName_build &sipStrings_goldencheetah[733] +#define sipNameNr_line 739 +#define sipName_line &sipStrings_goldencheetah[739] +#define sipNameNr_join 744 +#define sipName_join &sipStrings_goldencheetah[744] +#define sipNameNr_name 686 +#define sipName_name &sipStrings_goldencheetah[686] +#define sipNameNr_type 749 +#define sipName_type &sipStrings_goldencheetah[749] +#define sipNameNr_date 754 +#define sipName_date &sipStrings_goldencheetah[754] +#define sipNameNr_log 759 +#define sipName_log &sipStrings_goldencheetah[759] #define sipNameNr_max 120 #define sipName_max &sipStrings_goldencheetah[120] -#define sipNameNr_min 756 -#define sipName_min &sipStrings_goldencheetah[756] -#define sipNameNr_all 760 -#define sipName_all &sipStrings_goldencheetah[760] -#define sipNameNr_url 764 -#define sipName_url &sipStrings_goldencheetah[764] +#define sipNameNr_min 763 +#define sipName_min &sipStrings_goldencheetah[763] +#define sipNameNr_all 767 +#define sipName_all &sipStrings_goldencheetah[767] +#define sipNameNr_url 771 +#define sipName_url &sipStrings_goldencheetah[771] #define sipMalloc sipAPI_goldencheetah->api_malloc #define sipFree sipAPI_goldencheetah->api_free diff --git a/src/Python/SIP/sipgoldencheetahBindings.cpp b/src/Python/SIP/sipgoldencheetahBindings.cpp index c37c9319e..b1ce96d97 100644 --- a/src/Python/SIP/sipgoldencheetahBindings.cpp +++ b/src/Python/SIP/sipgoldencheetahBindings.cpp @@ -1056,19 +1056,21 @@ static PyObject *meth_Bindings_configChart(PyObject *sipSelf, PyObject *sipArgs, int a0State = 0; int a1; bool a2; + int a3; const ::Bindings *sipCpp; static const char *sipKwdList[] = { sipName_title, sipName_type, sipName_animate, + sipName_legpos, }; - if (sipParseKwdArgs(&sipParseErr, sipArgs, sipKwds, sipKwdList, NULL, "BJ1ib", &sipSelf, sipType_Bindings, &sipCpp, sipType_QString,&a0, &a0State, &a1, &a2)) + if (sipParseKwdArgs(&sipParseErr, sipArgs, sipKwds, sipKwdList, NULL, "BJ1ibi", &sipSelf, sipType_Bindings, &sipCpp, sipType_QString,&a0, &a0State, &a1, &a2, &a3)) { bool sipRes; - sipRes = sipCpp->configChart(*a0,a1,a2); + sipRes = sipCpp->configChart(*a0,a1,a2,a3); sipReleaseType(a0,sipType_QString,a0State); return PyBool_FromLong(sipRes); diff --git a/src/Python/SIP/sipgoldencheetahcmodule.cpp b/src/Python/SIP/sipgoldencheetahcmodule.cpp index 1fc429e0d..e17fe504f 100644 --- a/src/Python/SIP/sipgoldencheetahcmodule.cpp +++ b/src/Python/SIP/sipgoldencheetahcmodule.cpp @@ -74,6 +74,7 @@ const char sipStrings_goldencheetah[] = { 's', 'y', 'm', 'b', 'o', 'l', 0, 'c', 'o', 'l', 'o', 'r', 's', 0, 'l', 'a', 'b', 'e', 'l', 's', 0, + 'l', 'e', 'g', 'p', 'o', 's', 0, 'm', 'e', 't', 'r', 'i', 'c', 0, 's', 'e', 'a', 's', 'o', 'n', 0, 'f', 'i', 'l', 't', 'e', 'r', 0, diff --git a/src/Resources/python/library.py b/src/Resources/python/library.py index 996632bc8..247ae919d 100644 --- a/src/Resources/python/library.py +++ b/src/Resources/python/library.py @@ -29,8 +29,8 @@ def __GCactivityXdata(name="", activity=None): return rd # setting up the chart -def __GCsetChart(title="",type=1,animate=False): - GC.configChart(title,type,animate) +def __GCsetChart(title="",type=1,animate=False,legpos=2): + GC.configChart(title,type,animate,legpos) # add a curve def __GCsetCurve(name="",x=list(),y=list(),xaxis="x",yaxis="y", labels=list(), colors=list(),line=1,symbol=0,size=15,color="cyan",opacity=0,opengl=True): @@ -52,6 +52,13 @@ GC.setChart=__GCsetChart GC.addCurve=__GCsetCurve GC.setAxis=__GCconfigAxis +# line style +GC_LINE_NONE=0 +GC_LINE_SOLID=1 +GC_LINE_DASH=2 +GC_LINE_DOT=3 +GC_LINE_DASHDOT=4 + # constants GC_ALIGN_BOTTOM=0 GC_ALIGN_LEFT=1