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