Wt examples
3.2.3
|
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 #include <boost/date_time/gregorian/greg_year.hpp> 00013 00014 #include <Wt/WAbstractItemModel> 00015 #include <Wt/WApplication> 00016 #include <Wt/WCheckBox> 00017 #include <Wt/WComboBox> 00018 #include <Wt/WDoubleValidator> 00019 #include <Wt/WDate> 00020 #include <Wt/WEnvironment> 00021 #include <Wt/WIntValidator> 00022 #include <Wt/WLineEdit> 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 = boost::lexical_cast<double>(edit->text().toUTF8()); 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(boost::lexical_cast<std::string>(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(boost::lexical_cast<std::string>(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(boost::lexical_cast<std::string>(axis.minimum())); 00341 sc.minimumEdit->setValidator(anyNumberValidator); 00342 sc.minimumEdit->setEnabled(!autoValues); 00343 connectSignals(sc.minimumEdit); 00344 00345 sc.maximumEdit = new WLineEdit(axisConfig->elementAt(j, 5)); 00346 sc.maximumEdit->setText(boost::lexical_cast<std::string>(axis.maximum())); 00347 sc.maximumEdit->setValidator(anyNumberValidator); 00348 sc.maximumEdit->setEnabled(!autoValues); 00349 connectSignals(sc.maximumEdit); 00350 00351 sc.autoEdit = new WCheckBox(axisConfig->elementAt(j, 3)); 00352 sc.autoEdit->setChecked(autoValues); 00353 connectSignals(sc.autoEdit); 00354 sc.autoEdit->checked().connect(sc.maximumEdit, &WLineEdit::disable); 00355 sc.autoEdit->unChecked().connect(sc.maximumEdit, &WLineEdit::enable); 00356 sc.autoEdit->checked().connect(sc.minimumEdit, &WLineEdit::disable); 00357 sc.autoEdit->unChecked().connect(sc.minimumEdit, &WLineEdit::enable); 00358 00359 sc.gridLinesEdit = new WCheckBox(axisConfig->elementAt(j, 6)); 00360 connectSignals(sc.gridLinesEdit); 00361 00362 sc.labelAngleEdit = new WLineEdit(axisConfig->elementAt(j, 7)); 00363 sc.labelAngleEdit->setText("0"); 00364 sc.labelAngleEdit->setValidator(angleValidator); 00365 connectSignals(sc.labelAngleEdit); 00366 00367 axisConfig->rowAt(j)->setStyleClass("trdata"); 00368 00369 axisControls_.push_back(sc); 00370 } 00371 00372 p = list->addWidget("Axis properties", axisConfig); 00373 p->setMargin(WLength::Auto, Left | Right); 00374 p->resize(880, WLength::Auto); 00375 p->setMargin(20, Top | Bottom); 00376 00377 /* 00378 * If we do not have JavaScript, then add a button to reflect changes to 00379 * the chart. 00380 */ 00381 if (!WApplication::instance()->environment().javaScript()) { 00382 WPushButton *b = new WPushButton(this); 00383 b->setText("Update chart"); 00384 b->setInline(false); // so we can add margin to center horizontally 00385 b->setMargin(WLength::Auto, Left | Right); 00386 b->clicked().connect(this, &ChartConfig::update); 00387 } 00388 } 00389 00390 void ChartConfig::setValueFill(FillRangeType fill) 00391 { 00392 fill_ = fill; 00393 } 00394 00395 void ChartConfig::update() 00396 { 00397 bool haveLegend = false; 00398 std::vector<WDataSeries> series; 00399 00400 for (int i = 1; i < chart_->model()->columnCount(); ++i) { 00401 SeriesControl& sc = seriesControls_[i-1]; 00402 00403 if (sc.enabledEdit->isChecked()) { 00404 WDataSeries s(i); 00405 00406 switch (sc.typeEdit->currentIndex()) { 00407 case 0: 00408 s.setType(PointSeries); 00409 if (sc.markerEdit->currentIndex() == 0) 00410 sc.markerEdit->setCurrentIndex(1); 00411 break; 00412 case 1: 00413 s.setType(LineSeries); 00414 sc.markerEdit->setCurrentIndex(0); 00415 break; 00416 case 2: 00417 s.setType(CurveSeries); 00418 sc.markerEdit->setCurrentIndex(0); 00419 break; 00420 case 3: 00421 s.setType(BarSeries); 00422 sc.markerEdit->setCurrentIndex(0); 00423 break; 00424 case 4: 00425 s.setType(LineSeries); 00426 s.setFillRange(fill_); 00427 sc.markerEdit->setCurrentIndex(0); 00428 break; 00429 case 5: 00430 s.setType(CurveSeries); 00431 s.setFillRange(fill_); 00432 sc.markerEdit->setCurrentIndex(0); 00433 break; 00434 case 6: 00435 s.setType(BarSeries); 00436 s.setStacked(true); 00437 sc.markerEdit->setCurrentIndex(0); 00438 break; 00439 case 7: 00440 s.setType(LineSeries); 00441 s.setFillRange(fill_); 00442 s.setStacked(true); 00443 sc.markerEdit->setCurrentIndex(0); 00444 break; 00445 case 8: 00446 s.setType(CurveSeries); 00447 s.setFillRange(fill_); 00448 s.setStacked(true); 00449 sc.markerEdit->setCurrentIndex(0); 00450 } 00451 00452 //set WPainterPath to draw a diamond 00453 if(sc.markerEdit->currentIndex() == CustomMarker){ 00454 WPainterPath pp = WPainterPath(); 00455 pp.moveTo(-6, 0); 00456 pp.lineTo(0, 6); 00457 pp.lineTo(6, 0); 00458 pp.lineTo(0, -6); 00459 pp.lineTo(-6, 0); 00460 s.setCustomMarker(pp); 00461 } 00462 00463 s.setMarker(static_cast<MarkerType>(sc.markerEdit->currentIndex())); 00464 00465 if (sc.axisEdit->currentIndex() == 1) { 00466 s.bindToAxis(Y2Axis); 00467 } 00468 00469 if (sc.legendEdit->isChecked()) { 00470 s.setLegendEnabled(true); 00471 haveLegend = true; 00472 } else 00473 s.setLegendEnabled(false); 00474 00475 if (sc.shadowEdit->isChecked()) { 00476 s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3)); 00477 } else 00478 s.setShadow(WShadow()); 00479 00480 switch (sc.labelsEdit->currentIndex()) { 00481 case 1: 00482 s.setLabelsEnabled(XAxis); 00483 break; 00484 case 2: 00485 s.setLabelsEnabled(YAxis); 00486 break; 00487 case 3: 00488 s.setLabelsEnabled(XAxis); 00489 s.setLabelsEnabled(YAxis); 00490 break; 00491 } 00492 00493 series.push_back(s); 00494 } 00495 } 00496 00497 chart_->setSeries(series); 00498 00499 for (int i = 0; i < 3; ++i) { 00500 AxisControl& sc = axisControls_[i]; 00501 WAxis& axis = chart_->axis(static_cast<Axis>(i)); 00502 00503 axis.setVisible(sc.visibleEdit->isChecked()); 00504 00505 if (sc.scaleEdit->count() != 1) { 00506 int k = sc.scaleEdit->currentIndex(); 00507 if (axis.id() != XAxis) 00508 k += 1; 00509 else { 00510 if (k == 0) 00511 chart_->setType(CategoryChart); 00512 else 00513 chart_->setType(ScatterPlot); 00514 } 00515 00516 switch (k) { 00517 case 1: 00518 axis.setScale(LinearScale); break; 00519 case 2: 00520 axis.setScale(LogScale); break; 00521 case 3: 00522 axis.setScale(DateScale); break; 00523 } 00524 } 00525 00526 if (sc.autoEdit->isChecked()) 00527 axis.setAutoLimits(MinimumValue | MaximumValue); 00528 else { 00529 if (validate(sc.minimumEdit) && validate(sc.maximumEdit)) { 00530 double min, max; 00531 getDouble(sc.minimumEdit, min); 00532 getDouble(sc.maximumEdit, max); 00533 00534 if (axis.scale() == LogScale) 00535 if (min <= 0) 00536 min = 0.0001; 00537 00538 if (axis.scale() == DateScale){ 00539 //the number of julian days until year 1986 00540 WDate dMin = WDate(1900,1,1); 00541 double gregDaysMin = (double)dMin.toJulianDay(); 00542 //the number of julian days until year 1988 00543 WDate dMax = WDate(3000,1,1); 00544 double gregDaysMax = (double)dMax.toJulianDay(); 00545 00546 bool greg_year_validation = 00547 (min > gregDaysMin && 00548 min < gregDaysMax && 00549 max > gregDaysMin && 00550 max < gregDaysMax); 00551 00552 if(!greg_year_validation){ 00553 min = gregDaysMin; 00554 max = gregDaysMax; 00555 } 00556 } 00557 00558 axis.setRange(min, max); 00559 } 00560 00561 } 00562 00563 if (validate(sc.labelAngleEdit)) { 00564 double angle; 00565 getDouble(sc.labelAngleEdit, angle); 00566 axis.setLabelAngle(angle); 00567 } 00568 00569 axis.setGridLinesEnabled(sc.gridLinesEdit->isChecked()); 00570 } 00571 00572 chart_->setTitle(titleEdit_->text()); 00573 00574 if (validate(chartWidthEdit_) && validate(chartHeightEdit_)) { 00575 double width, height; 00576 getDouble(chartWidthEdit_, width); 00577 getDouble(chartHeightEdit_, height); 00578 chart_->resize(width, height); 00579 } 00580 00581 switch (chartOrientationEdit_->currentIndex()) { 00582 case 0: 00583 chart_->setOrientation(Vertical); break; 00584 case 1: 00585 chart_->setOrientation(Horizontal); break; 00586 } 00587 00588 chart_->setLegendEnabled(haveLegend); 00589 00590 if (haveLegend) { 00591 LegendLocation location = LegendOutside; 00592 Side side = Right; 00593 AlignmentFlag alignment = AlignMiddle; 00594 00595 switch (legendLocationEdit_->currentIndex()) { 00596 case 0: location = LegendOutside; break; 00597 case 1: location = LegendInside; break; 00598 } 00599 00600 switch (legendSideEdit_->currentIndex()) { 00601 case 0: side = Top; break; 00602 case 1: side = Right; break; 00603 case 2: side = Bottom; break; 00604 case 3: side = Left; break; 00605 } 00606 00607 if (side == Left || side == Right) { 00608 if (legendAlignmentEdit_->currentIndex() < 3) 00609 legendAlignmentEdit_->setCurrentIndex(4); 00610 } else { 00611 if (legendAlignmentEdit_->currentIndex() >= 3) 00612 legendAlignmentEdit_->setCurrentIndex(2); 00613 } 00614 00615 switch (legendAlignmentEdit_->currentIndex()) { 00616 case 0: alignment = AlignLeft; break; 00617 case 1: alignment = AlignCenter; break; 00618 case 2: alignment = AlignRight; break; 00619 case 3: alignment = AlignTop; break; 00620 case 4: alignment = AlignMiddle; break; 00621 case 5: alignment = AlignBottom; break; 00622 } 00623 00624 chart_->setLegendLocation(location, side, alignment); 00625 00626 chart_->setLegendColumns((side == Top || side == Bottom ) ? 2 : 1, 00627 WLength(100)); 00628 } 00629 00630 for (unsigned i = 0; i < 4; ++i) { 00631 Side sides[] = { Top, Right, Bottom, Left }; 00632 00633 bool legendRoom = 00634 haveLegend 00635 && chart_->legendLocation() == LegendOutside 00636 && chart_->legendSide() == sides[i]; 00637 00638 int padding; 00639 00640 if (i % 2 == 0) 00641 padding = legendRoom ? 80 : 40; 00642 else 00643 padding = legendRoom ? 200 : 80; 00644 00645 chart_->setPlotAreaPadding(padding, sides[i]); 00646 } 00647 } 00648 00649 bool ChartConfig::validate(WFormWidget *w) 00650 { 00651 bool valid = w->validate() == WValidator::Valid; 00652 00653 if (!WApplication::instance()->environment().javaScript()) { 00654 w->setStyleClass(valid ? "" : "Wt-invalid"); 00655 w->setToolTip(valid ? "" : "Invalid value"); 00656 } 00657 00658 return valid; 00659 } 00660 00661 void ChartConfig::connectSignals(WFormWidget *w) 00662 { 00663 w->changed().connect(this, &ChartConfig::update); 00664 if (dynamic_cast<WLineEdit *>(w)) 00665 w->enterPressed().connect(this, &ChartConfig::update); 00666 }