Wt examples
3.3.0
|
00001 /* 00002 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium. 00003 * 00004 * See the LICENSE file for terms of use. 00005 */ 00006 00007 #include "ChartConfig.h" 00008 #include "PanelList.h" 00009 00010 #include <iostream> 00011 #include <boost/date_time/gregorian/greg_year.hpp> 00012 00013 #include <Wt/WAbstractItemModel> 00014 #include <Wt/WApplication> 00015 #include <Wt/WCheckBox> 00016 #include <Wt/WComboBox> 00017 #include <Wt/WDoubleValidator> 00018 #include <Wt/WDate> 00019 #include <Wt/WEnvironment> 00020 #include <Wt/WIntValidator> 00021 #include <Wt/WLineEdit> 00022 #include <Wt/WLocale> 00023 #include <Wt/WPanel> 00024 #include <Wt/WPushButton> 00025 #include <Wt/WStandardItemModel> 00026 #include <Wt/WTable> 00027 #include <Wt/WText> 00028 #include <Wt/WPainterPath> 00029 00030 #include <Wt/Chart/WCartesianChart> 00031 00032 using namespace Wt; 00033 using namespace Wt::Chart; 00034 00035 namespace { 00036 void addHeader(WTable *t, const char *value) { 00037 t->elementAt(0, t->columnCount())->addWidget(new WText(value)); 00038 } 00039 00040 void addEntry(WAbstractItemModel *model, const char *value) { 00041 model->insertRows(model->rowCount(), 1); 00042 model->setData(model->rowCount()-1, 0, boost::any(std::string(value))); 00043 } 00044 00045 bool getDouble(WLineEdit *edit, double& value) { 00046 try { 00047 value = WLocale::currentLocale().toDouble(edit->text()); 00048 return true; 00049 } catch (...) { 00050 return false; 00051 } 00052 } 00053 00054 int seriesIndexOf(WCartesianChart* chart, int modelColumn) { 00055 for (unsigned i = 0; i < chart->series().size(); ++i) 00056 if (chart->series()[i].modelColumn() == modelColumn) 00057 return i; 00058 00059 return -1; 00060 } 00061 } 00062 00063 ChartConfig::ChartConfig(WCartesianChart *chart, WContainerWidget *parent) 00064 : WContainerWidget(parent), 00065 chart_(chart), 00066 fill_(MinimumValueFill) 00067 { 00068 chart_->setLegendStyle(chart_->legendFont(), WPen(black), 00069 WBrush(WColor(0xFF, 0xFA, 0xE5))); 00070 chart->initLayout(); 00071 00072 PanelList *list = new PanelList(this); 00073 00074 WIntValidator *sizeValidator = new WIntValidator(200, 2000, this); 00075 sizeValidator->setMandatory(true); 00076 00077 WDoubleValidator *anyNumberValidator = new WDoubleValidator(this); 00078 anyNumberValidator->setMandatory(true); 00079 00080 WDoubleValidator *angleValidator = new WDoubleValidator(-90, 90, this); 00081 angleValidator->setMandatory(true); 00082 00083 // ---- Chart properties ---- 00084 00085 WStandardItemModel *orientation = new WStandardItemModel(0, 1, this); 00086 addEntry(orientation, "Vertical"); 00087 addEntry(orientation, "Horizontal"); 00088 00089 WStandardItemModel *legendLocation = new WStandardItemModel(0, 1, this); 00090 addEntry(legendLocation, "Outside"); 00091 addEntry(legendLocation, "Inside"); 00092 00093 WStandardItemModel *legendSide = new WStandardItemModel(0, 1, this); 00094 addEntry(legendSide, "Top"); 00095 addEntry(legendSide, "Right"); 00096 addEntry(legendSide, "Bottom"); 00097 addEntry(legendSide, "Left"); 00098 00099 WStandardItemModel *legendAlignment = new WStandardItemModel(0, 1, this); 00100 addEntry(legendAlignment, "AlignLeft"); 00101 addEntry(legendAlignment, "AlignCenter"); 00102 addEntry(legendAlignment, "AlignRight"); 00103 addEntry(legendAlignment, "AlignTop"); 00104 addEntry(legendAlignment, "AlignMiddle"); 00105 addEntry(legendAlignment, "AlignBottom"); 00106 00107 WTable *chartConfig = new WTable(); 00108 chartConfig->setMargin(WLength::Auto, Left | Right); 00109 00110 int row = 0; 00111 chartConfig->elementAt(row, 0)->addWidget(new WText("Title:")); 00112 titleEdit_ = new WLineEdit(chartConfig->elementAt(row, 1)); 00113 connectSignals(titleEdit_); 00114 ++row; 00115 00116 chartConfig->elementAt(row, 0)->addWidget(new WText("Width:")); 00117 chartWidthEdit_ = new WLineEdit(chartConfig->elementAt(row, 1)); 00118 chartWidthEdit_ 00119 ->setText(WLocale::currentLocale().toString(chart_->width().value())); 00120 chartWidthEdit_->setValidator(sizeValidator); 00121 chartWidthEdit_->setMaxLength(4); 00122 connectSignals(chartWidthEdit_); 00123 ++row; 00124 00125 chartConfig->elementAt(row, 0)->addWidget(new WText("Height:")); 00126 chartHeightEdit_ = new WLineEdit(chartConfig->elementAt(row, 1)); 00127 chartHeightEdit_ 00128 ->setText(WLocale::currentLocale().toString(chart_->height().value())); 00129 chartHeightEdit_->setValidator(sizeValidator); 00130 chartHeightEdit_->setMaxLength(4); 00131 connectSignals(chartHeightEdit_); 00132 ++row; 00133 00134 chartConfig->elementAt(row, 0)->addWidget(new WText("Orientation:")); 00135 chartOrientationEdit_ = new WComboBox(chartConfig->elementAt(row, 1)); 00136 chartOrientationEdit_->setModel(orientation); 00137 connectSignals(chartOrientationEdit_); 00138 ++row; 00139 00140 chartConfig->elementAt(row, 0)->addWidget(new WText("Legend location:")); 00141 legendLocationEdit_ = new WComboBox(chartConfig->elementAt(row, 1)); 00142 legendLocationEdit_->setModel(legendLocation); 00143 connectSignals(legendLocationEdit_); 00144 ++row; 00145 00146 chartConfig->elementAt(row, 0)->addWidget(new WText("Legend side:")); 00147 legendSideEdit_ = new WComboBox(chartConfig->elementAt(row, 1)); 00148 legendSideEdit_->setModel(legendSide); 00149 legendSideEdit_->setCurrentIndex(1); 00150 connectSignals(legendSideEdit_); 00151 ++row; 00152 00153 chartConfig->elementAt(row, 0)->addWidget(new WText("Legend alignment:")); 00154 legendAlignmentEdit_ = new WComboBox(chartConfig->elementAt(row, 1)); 00155 legendAlignmentEdit_->setModel(legendAlignment); 00156 legendAlignmentEdit_->setCurrentIndex(4); 00157 connectSignals(legendAlignmentEdit_); 00158 ++row; 00159 00160 for (int i = 0; i < chartConfig->rowCount(); ++i) { 00161 chartConfig->elementAt(i, 0)->setStyleClass("tdhead"); 00162 chartConfig->elementAt(i, 1)->setStyleClass("tddata"); 00163 } 00164 00165 WPanel *p = list->addWidget("Chart properties", chartConfig); 00166 p->setMargin(WLength::Auto, Left | Right); 00167 p->resize(880, WLength::Auto); 00168 p->setMargin(20, Top | Bottom); 00169 00170 if (chart_->isLegendEnabled()) 00171 chart_->setPlotAreaPadding(200, Right); 00172 00173 // ---- Series properties ---- 00174 00175 WStandardItemModel *types = new WStandardItemModel(0, 1, this); 00176 addEntry(types, "Points"); 00177 addEntry(types, "Line"); 00178 addEntry(types, "Curve"); 00179 addEntry(types, "Bar"); 00180 addEntry(types, "Line Area"); 00181 addEntry(types, "Curve Area"); 00182 addEntry(types, "Stacked Bar"); 00183 addEntry(types, "Stacked Line Area"); 00184 addEntry(types, "Stacked Curve Area"); 00185 00186 WStandardItemModel *markers = new WStandardItemModel(0, 1, this); 00187 addEntry(markers, "None"); 00188 addEntry(markers, "Square"); 00189 addEntry(markers, "Circle"); 00190 addEntry(markers, "Cross"); 00191 addEntry(markers, "X cross"); 00192 addEntry(markers, "Triangle"); 00193 addEntry(markers, "Diamond"); 00194 00195 WStandardItemModel *axes = new WStandardItemModel(0, 1, this); 00196 addEntry(axes, "1st Y axis"); 00197 addEntry(axes, "2nd Y axis"); 00198 00199 WStandardItemModel *labels = new WStandardItemModel(0, 1, this); 00200 addEntry(labels, "None"); 00201 addEntry(labels, "X"); 00202 addEntry(labels, "Y"); 00203 addEntry(labels, "X: Y"); 00204 00205 WTable *seriesConfig = new WTable(); 00206 seriesConfig->setMargin(WLength::Auto, Left | Right); 00207 00208 ::addHeader(seriesConfig, "Name"); 00209 ::addHeader(seriesConfig, "Enabled"); 00210 ::addHeader(seriesConfig, "Type"); 00211 ::addHeader(seriesConfig, "Marker"); 00212 ::addHeader(seriesConfig, "Y axis"); 00213 ::addHeader(seriesConfig, "Legend"); 00214 ::addHeader(seriesConfig, "Shadow"); 00215 ::addHeader(seriesConfig, "Value labels"); 00216 00217 seriesConfig->rowAt(0)->setStyleClass("trhead"); 00218 00219 for (int j = 1; j < chart->model()->columnCount(); ++j) { 00220 SeriesControl sc; 00221 00222 new WText(asString(chart->model()->headerData(j)), 00223 seriesConfig->elementAt(j, 0)); 00224 00225 sc.enabledEdit = new WCheckBox(seriesConfig->elementAt(j, 1)); 00226 connectSignals(sc.enabledEdit); 00227 00228 sc.typeEdit = new WComboBox(seriesConfig->elementAt(j, 2)); 00229 sc.typeEdit->setModel(types); 00230 connectSignals(sc.typeEdit); 00231 00232 sc.markerEdit = new WComboBox(seriesConfig->elementAt(j, 3)); 00233 sc.markerEdit->setModel(markers); 00234 connectSignals(sc.markerEdit); 00235 00236 sc.axisEdit = new WComboBox(seriesConfig->elementAt(j, 4)); 00237 sc.axisEdit->setModel(axes); 00238 connectSignals(sc.axisEdit); 00239 00240 sc.legendEdit = new WCheckBox(seriesConfig->elementAt(j, 5)); 00241 connectSignals(sc.legendEdit); 00242 00243 sc.shadowEdit = new WCheckBox(seriesConfig->elementAt(j, 6)); 00244 connectSignals(sc.shadowEdit); 00245 00246 sc.labelsEdit = new WComboBox(seriesConfig->elementAt(j, 7)); 00247 sc.labelsEdit->setModel(labels); 00248 connectSignals(sc.labelsEdit); 00249 00250 int si = seriesIndexOf(chart, j); 00251 00252 if (si != -1) { 00253 sc.enabledEdit->setChecked(); 00254 const WDataSeries& s = chart_->series(j); 00255 switch (s.type()) { 00256 case PointSeries: 00257 sc.typeEdit->setCurrentIndex(0); break; 00258 case LineSeries: 00259 sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ? 00260 (s.isStacked() ? 7 : 4) : 1); break; 00261 case CurveSeries: 00262 sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ? 00263 (s.isStacked() ? 8 : 5) : 2); break; 00264 case BarSeries: 00265 sc.typeEdit->setCurrentIndex(s.isStacked() ? 6 : 3); 00266 } 00267 00268 sc.markerEdit->setCurrentIndex((int)s.marker()); 00269 sc.legendEdit->setChecked(s.isLegendEnabled()); 00270 sc.shadowEdit->setChecked(s.shadow() != WShadow()); 00271 } 00272 00273 seriesControls_.push_back(sc); 00274 00275 seriesConfig->rowAt(j)->setStyleClass("trdata"); 00276 } 00277 00278 p = list->addWidget("Series properties", seriesConfig); 00279 p->expand(); 00280 p->setMargin(WLength::Auto, Left | Right); 00281 p->resize(880, WLength::Auto); 00282 p->setMargin(20, Top | Bottom); 00283 00284 // ---- Axis properties ---- 00285 00286 WStandardItemModel *yScales = new WStandardItemModel(0, 1, this); 00287 addEntry(yScales, "Linear scale"); 00288 addEntry(yScales, "Log scale"); 00289 00290 WStandardItemModel *xScales = new WStandardItemModel(0, 1, this); 00291 addEntry(xScales, "Categories"); 00292 addEntry(xScales, "Linear scale"); 00293 addEntry(xScales, "Log scale"); 00294 addEntry(xScales, "Date scale"); 00295 00296 WTable *axisConfig = new WTable(); 00297 axisConfig->setMargin(WLength::Auto, Left | Right); 00298 00299 ::addHeader(axisConfig, "Axis"); 00300 ::addHeader(axisConfig, "Visible"); 00301 ::addHeader(axisConfig, "Scale"); 00302 ::addHeader(axisConfig, "Automatic"); 00303 ::addHeader(axisConfig, "Minimum"); 00304 ::addHeader(axisConfig, "Maximum"); 00305 ::addHeader(axisConfig, "Gridlines"); 00306 ::addHeader(axisConfig, "Label angle"); 00307 00308 axisConfig->rowAt(0)->setStyleClass("trhead"); 00309 00310 for (int i = 0; i < 3; ++i) { 00311 const char *axisName[] = { "X axis", "1st Y axis", "2nd Y axis" }; 00312 int j = i + 1; 00313 00314 const WAxis& axis = chart_->axis(static_cast<Axis>(i)); 00315 AxisControl sc; 00316 00317 new WText(WString(axisName[i], UTF8), axisConfig->elementAt(j, 0)); 00318 00319 sc.visibleEdit = new WCheckBox(axisConfig->elementAt(j, 1)); 00320 sc.visibleEdit->setChecked(axis.isVisible()); 00321 connectSignals(sc.visibleEdit); 00322 00323 sc.scaleEdit = new WComboBox(axisConfig->elementAt(j, 2)); 00324 if (axis.scale() == CategoryScale) 00325 sc.scaleEdit->addItem("Category scale"); 00326 else { 00327 if (axis.id() == XAxis) { 00328 sc.scaleEdit->setModel(xScales); 00329 sc.scaleEdit->setCurrentIndex(axis.scale()); 00330 } else { 00331 sc.scaleEdit->setModel(yScales); 00332 sc.scaleEdit->setCurrentIndex(axis.scale() - 1); 00333 } 00334 } 00335 connectSignals(sc.scaleEdit); 00336 00337 bool autoValues = axis.autoLimits() == (MinimumValue | MaximumValue); 00338 00339 sc.minimumEdit = new WLineEdit(axisConfig->elementAt(j, 4)); 00340 sc.minimumEdit->setText(WLocale::currentLocale() 00341 .toString(axis.minimum())); 00342 sc.minimumEdit->setValidator(anyNumberValidator); 00343 sc.minimumEdit->setEnabled(!autoValues); 00344 connectSignals(sc.minimumEdit); 00345 00346 sc.maximumEdit = new WLineEdit(axisConfig->elementAt(j, 5)); 00347 sc.maximumEdit->setText(WLocale::currentLocale() 00348 .toString(axis.maximum())); 00349 sc.maximumEdit->setValidator(anyNumberValidator); 00350 sc.maximumEdit->setEnabled(!autoValues); 00351 connectSignals(sc.maximumEdit); 00352 00353 sc.autoEdit = new WCheckBox(axisConfig->elementAt(j, 3)); 00354 sc.autoEdit->setChecked(autoValues); 00355 connectSignals(sc.autoEdit); 00356 sc.autoEdit->checked().connect(sc.maximumEdit, &WLineEdit::disable); 00357 sc.autoEdit->unChecked().connect(sc.maximumEdit, &WLineEdit::enable); 00358 sc.autoEdit->checked().connect(sc.minimumEdit, &WLineEdit::disable); 00359 sc.autoEdit->unChecked().connect(sc.minimumEdit, &WLineEdit::enable); 00360 00361 sc.gridLinesEdit = new WCheckBox(axisConfig->elementAt(j, 6)); 00362 connectSignals(sc.gridLinesEdit); 00363 00364 sc.labelAngleEdit = new WLineEdit(axisConfig->elementAt(j, 7)); 00365 sc.labelAngleEdit->setText("0"); 00366 sc.labelAngleEdit->setValidator(angleValidator); 00367 connectSignals(sc.labelAngleEdit); 00368 00369 axisConfig->rowAt(j)->setStyleClass("trdata"); 00370 00371 axisControls_.push_back(sc); 00372 } 00373 00374 p = list->addWidget("Axis properties", axisConfig); 00375 p->setMargin(WLength::Auto, Left | Right); 00376 p->resize(880, WLength::Auto); 00377 p->setMargin(20, Top | Bottom); 00378 00379 /* 00380 * If we do not have JavaScript, then add a button to reflect changes to 00381 * the chart. 00382 */ 00383 if (!WApplication::instance()->environment().javaScript()) { 00384 WPushButton *b = new WPushButton(this); 00385 b->setText("Update chart"); 00386 b->setInline(false); // so we can add margin to center horizontally 00387 b->setMargin(WLength::Auto, Left | Right); 00388 b->clicked().connect(this, &ChartConfig::update); 00389 } 00390 } 00391 00392 void ChartConfig::setValueFill(FillRangeType fill) 00393 { 00394 fill_ = fill; 00395 } 00396 00397 void ChartConfig::update() 00398 { 00399 bool haveLegend = false; 00400 std::vector<WDataSeries> series; 00401 00402 for (int i = 1; i < chart_->model()->columnCount(); ++i) { 00403 SeriesControl& sc = seriesControls_[i-1]; 00404 00405 if (sc.enabledEdit->isChecked()) { 00406 WDataSeries s(i); 00407 00408 switch (sc.typeEdit->currentIndex()) { 00409 case 0: 00410 s.setType(PointSeries); 00411 if (sc.markerEdit->currentIndex() == 0) 00412 sc.markerEdit->setCurrentIndex(1); 00413 break; 00414 case 1: 00415 s.setType(LineSeries); 00416 sc.markerEdit->setCurrentIndex(0); 00417 break; 00418 case 2: 00419 s.setType(CurveSeries); 00420 sc.markerEdit->setCurrentIndex(0); 00421 break; 00422 case 3: 00423 s.setType(BarSeries); 00424 sc.markerEdit->setCurrentIndex(0); 00425 break; 00426 case 4: 00427 s.setType(LineSeries); 00428 s.setFillRange(fill_); 00429 sc.markerEdit->setCurrentIndex(0); 00430 break; 00431 case 5: 00432 s.setType(CurveSeries); 00433 s.setFillRange(fill_); 00434 sc.markerEdit->setCurrentIndex(0); 00435 break; 00436 case 6: 00437 s.setType(BarSeries); 00438 s.setStacked(true); 00439 sc.markerEdit->setCurrentIndex(0); 00440 break; 00441 case 7: 00442 s.setType(LineSeries); 00443 s.setFillRange(fill_); 00444 s.setStacked(true); 00445 sc.markerEdit->setCurrentIndex(0); 00446 break; 00447 case 8: 00448 s.setType(CurveSeries); 00449 s.setFillRange(fill_); 00450 s.setStacked(true); 00451 sc.markerEdit->setCurrentIndex(0); 00452 } 00453 00454 //set WPainterPath to draw a diamond 00455 if(sc.markerEdit->currentIndex() == CustomMarker){ 00456 WPainterPath pp = WPainterPath(); 00457 pp.moveTo(-6, 0); 00458 pp.lineTo(0, 6); 00459 pp.lineTo(6, 0); 00460 pp.lineTo(0, -6); 00461 pp.lineTo(-6, 0); 00462 s.setCustomMarker(pp); 00463 } 00464 00465 s.setMarker(static_cast<MarkerType>(sc.markerEdit->currentIndex())); 00466 00467 if (sc.axisEdit->currentIndex() == 1) { 00468 s.bindToAxis(Y2Axis); 00469 } 00470 00471 if (sc.legendEdit->isChecked()) { 00472 s.setLegendEnabled(true); 00473 haveLegend = true; 00474 } else 00475 s.setLegendEnabled(false); 00476 00477 if (sc.shadowEdit->isChecked()) { 00478 s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3)); 00479 } else 00480 s.setShadow(WShadow()); 00481 00482 switch (sc.labelsEdit->currentIndex()) { 00483 case 1: 00484 s.setLabelsEnabled(XAxis); 00485 break; 00486 case 2: 00487 s.setLabelsEnabled(YAxis); 00488 break; 00489 case 3: 00490 s.setLabelsEnabled(XAxis); 00491 s.setLabelsEnabled(YAxis); 00492 break; 00493 } 00494 00495 series.push_back(s); 00496 } 00497 } 00498 00499 chart_->setSeries(series); 00500 00501 for (int i = 0; i < 3; ++i) { 00502 AxisControl& sc = axisControls_[i]; 00503 WAxis& axis = chart_->axis(static_cast<Axis>(i)); 00504 00505 axis.setVisible(sc.visibleEdit->isChecked()); 00506 00507 if (sc.scaleEdit->count() != 1) { 00508 int k = sc.scaleEdit->currentIndex(); 00509 if (axis.id() != XAxis) 00510 k += 1; 00511 else { 00512 if (k == 0) 00513 chart_->setType(CategoryChart); 00514 else 00515 chart_->setType(ScatterPlot); 00516 } 00517 00518 switch (k) { 00519 case 1: 00520 axis.setScale(LinearScale); break; 00521 case 2: 00522 axis.setScale(LogScale); break; 00523 case 3: 00524 axis.setScale(DateScale); break; 00525 } 00526 } 00527 00528 if (sc.autoEdit->isChecked()) 00529 axis.setAutoLimits(MinimumValue | MaximumValue); 00530 else { 00531 if (validate(sc.minimumEdit) && validate(sc.maximumEdit)) { 00532 double min, max; 00533 getDouble(sc.minimumEdit, min); 00534 getDouble(sc.maximumEdit, max); 00535 00536 if (axis.scale() == LogScale) 00537 if (min <= 0) 00538 min = 0.0001; 00539 00540 if (axis.scale() == DateScale){ 00541 //the number of julian days until year 1986 00542 WDate dMin = WDate(1900,1,1); 00543 double gregDaysMin = (double)dMin.toJulianDay(); 00544 //the number of julian days until year 1988 00545 WDate dMax = WDate(3000,1,1); 00546 double gregDaysMax = (double)dMax.toJulianDay(); 00547 00548 bool greg_year_validation = 00549 (min > gregDaysMin && 00550 min < gregDaysMax && 00551 max > gregDaysMin && 00552 max < gregDaysMax); 00553 00554 if(!greg_year_validation){ 00555 min = gregDaysMin; 00556 max = gregDaysMax; 00557 } 00558 } 00559 00560 axis.setRange(min, max); 00561 } 00562 00563 } 00564 00565 if (validate(sc.labelAngleEdit)) { 00566 double angle; 00567 getDouble(sc.labelAngleEdit, angle); 00568 axis.setLabelAngle(angle); 00569 } 00570 00571 axis.setGridLinesEnabled(sc.gridLinesEdit->isChecked()); 00572 } 00573 00574 chart_->setTitle(titleEdit_->text()); 00575 00576 if (validate(chartWidthEdit_) && validate(chartHeightEdit_)) { 00577 double width, height; 00578 getDouble(chartWidthEdit_, width); 00579 getDouble(chartHeightEdit_, height); 00580 chart_->resize(width, height); 00581 } 00582 00583 switch (chartOrientationEdit_->currentIndex()) { 00584 case 0: 00585 chart_->setOrientation(Vertical); break; 00586 case 1: 00587 chart_->setOrientation(Horizontal); break; 00588 } 00589 00590 chart_->setLegendEnabled(haveLegend); 00591 00592 if (haveLegend) { 00593 LegendLocation location = LegendOutside; 00594 Side side = Right; 00595 AlignmentFlag alignment = AlignMiddle; 00596 00597 switch (legendLocationEdit_->currentIndex()) { 00598 case 0: location = LegendOutside; break; 00599 case 1: location = LegendInside; break; 00600 } 00601 00602 switch (legendSideEdit_->currentIndex()) { 00603 case 0: side = Top; break; 00604 case 1: side = Right; break; 00605 case 2: side = Bottom; break; 00606 case 3: side = Left; break; 00607 } 00608 00609 if (side == Left || side == Right) { 00610 if (legendAlignmentEdit_->currentIndex() < 3) 00611 legendAlignmentEdit_->setCurrentIndex(4); 00612 } else { 00613 if (legendAlignmentEdit_->currentIndex() >= 3) 00614 legendAlignmentEdit_->setCurrentIndex(2); 00615 } 00616 00617 switch (legendAlignmentEdit_->currentIndex()) { 00618 case 0: alignment = AlignLeft; break; 00619 case 1: alignment = AlignCenter; break; 00620 case 2: alignment = AlignRight; break; 00621 case 3: alignment = AlignTop; break; 00622 case 4: alignment = AlignMiddle; break; 00623 case 5: alignment = AlignBottom; break; 00624 } 00625 00626 chart_->setLegendLocation(location, side, alignment); 00627 00628 chart_->setLegendColumns((side == Top || side == Bottom ) ? 2 : 1, 00629 WLength(100)); 00630 } 00631 00632 for (unsigned i = 0; i < 4; ++i) { 00633 Side sides[] = { Top, Right, Bottom, Left }; 00634 00635 bool legendRoom = 00636 haveLegend 00637 && chart_->legendLocation() == LegendOutside 00638 && chart_->legendSide() == sides[i]; 00639 00640 int padding; 00641 00642 if (i % 2 == 0) 00643 padding = legendRoom ? 80 : 40; 00644 else 00645 padding = legendRoom ? 200 : 80; 00646 00647 chart_->setPlotAreaPadding(padding, sides[i]); 00648 } 00649 } 00650 00651 bool ChartConfig::validate(WFormWidget *w) 00652 { 00653 bool valid = w->validate() == WValidator::Valid; 00654 00655 if (!WApplication::instance()->environment().javaScript()) { 00656 w->setStyleClass(valid ? "" : "Wt-invalid"); 00657 w->setToolTip(valid ? "" : "Invalid value"); 00658 } 00659 00660 return valid; 00661 } 00662 00663 void ChartConfig::connectSignals(WFormWidget *w) 00664 { 00665 w->changed().connect(this, &ChartConfig::update); 00666 if (dynamic_cast<WLineEdit *>(w)) 00667 w->enterPressed().connect(this, &ChartConfig::update); 00668 }