![]() |
TinkerCell Core 1.0
TinkerCell's Core library providing all basic functionalities
|
00001 00002 /**************************************************************************** 00003 00004 Copyright (c) 2008 Deepak Chandran 00005 Contact: Deepak Chandran (dchandran1@gmail.com) 00006 See COPYRIGHT.TXT 00007 00008 A slider widget that calls a C function whenver values in the slider are changed. 00009 Uses CThread. 00010 00011 ****************************************************************************/ 00012 00013 #include <QRegExp> 00014 #include <QHBoxLayout> 00015 #include <QVBoxLayout> 00016 #include <QPushButton> 00017 #include "ConsoleWindow.h" 00018 #include "MainWindow.h" 00019 #include "NetworkHandle.h" 00020 #include "SymbolsTable.h" 00021 #include "MultithreadedSliderWidget.h" 00022 00023 namespace Tinkercell 00024 { 00025 void MultithreadedSliderWidget::setVisibleSliders(const QString& substring) 00026 { 00027 QStringList keys, allkeys; 00028 QRegExp regex(substring); 00029 for (int j=0; j < labels.size() && j < minline.size() && j < maxline.size() && j < valueline.size(); ++j) 00030 { 00031 if (labels[j] && (labels[j]->text().toLower().contains(substring.toLower()) || labels[j]->text().contains(regex))) 00032 keys += labels[j]->text(); 00033 allkeys += labels[j]->text(); 00034 } 00035 if (substring.isEmpty() || keys.isEmpty()) 00036 setVisibleSliders(allkeys); 00037 else 00038 setVisibleSliders(keys); 00039 } 00040 00041 void MultithreadedSliderWidget::setVisibleSliders(const QStringList& options) 00042 { 00043 QVector<bool> showList(labels.size(),false); 00044 for (int i=0; i < options.size(); ++i) 00045 { 00046 for (int j=0; j < labels.size() && j < minline.size() && j < maxline.size() && j < valueline.size(); ++j) 00047 { 00048 if (labels[j] && options.contains(labels[j]->text())) 00049 showList[j] = true; 00050 } 00051 } 00052 00053 for (int j=0; j < labels.size() && j < minline.size() && j < maxline.size() && j < valueline.size(); ++j) 00054 if (!showList[j]) 00055 { 00056 labels[j]->hide(); 00057 minline[j]->hide(); 00058 maxline[j]->hide(); 00059 valueline[j]->hide(); 00060 if (sliderWidgets.contains(labels[j]->text())) 00061 sliderWidgets[labels[j]->text()]->hide(); 00062 } 00063 else 00064 { 00065 labels[j]->show(); 00066 minline[j]->show(); 00067 maxline[j]->show(); 00068 valueline[j]->show(); 00069 if (sliderWidgets.contains(labels[j]->text())) 00070 sliderWidgets[labels[j]->text()]->show(); 00071 } 00072 } 00073 00074 MultithreadedSliderWidget::MultithreadedSliderWidget(MainWindow * parent, CThread * thread, Qt::Orientation orientation) 00075 : QWidget(parent), orientation(orientation), mainWindow(parent) 00076 { 00077 setAttribute(Qt::WA_DeleteOnClose,true); 00078 cthread = thread; 00079 setWindowFlags(Qt::Dialog); 00080 slidersLayout = 0; 00081 hide(); 00082 } 00083 00084 MultithreadedSliderWidget::MultithreadedSliderWidget(MainWindow * parent, const QString & lib, const QString & functionName, Qt::Orientation orientation) 00085 : QWidget(parent), orientation(orientation), mainWindow(parent) 00086 { 00087 setAttribute(Qt::WA_DeleteOnClose,true); 00088 cthread = new CThread(parent, lib); 00089 cthread->setMatrixFunction(functionName.toAscii().data()); 00090 setWindowFlags(Qt::Dialog); 00091 slidersLayout = 0; 00092 hide(); 00093 } 00094 00095 CThread * MultithreadedSliderWidget::thread() const 00096 { 00097 return cthread; 00098 } 00099 00100 void MultithreadedSliderWidget::setThread(CThread * t) 00101 { 00102 cthread = t; 00103 } 00104 00105 void MultithreadedSliderWidget::minmaxChanged() 00106 { 00107 if (sliders.isEmpty()) return; 00108 00109 double range,x; 00110 bool ok; 00111 00112 for (int i=0; i < sliders.size(); ++i) 00113 if (sliders[i]) 00114 disconnect(sliders[i],SIGNAL(valueChanged(int)),this,SLOT(sliderChanged(int))); 00115 00116 for (int i=0; i < sliders.size() && i < max.size() && i < min.size(); ++i) 00117 if (sliders[i]) 00118 { 00119 x = minline[i]->text().toDouble(&ok); 00120 if (ok) 00121 min[i] = x; 00122 else 00123 minline[i]->setText(QString::number(min[i])); 00124 00125 x = maxline[i]->text().toDouble(&ok); 00126 if (ok) 00127 max[i] = x; 00128 else 00129 maxline[i]->setText(QString::number(max[i])); 00130 00131 range = (max[i]-min[i]); 00132 sliders[i]->setValue((int)((values.value(i,0) - min[i]) * 100.0/range)); 00133 } 00134 for (int i=0; i < sliders.size(); ++i) 00135 if (sliders[i]) 00136 connect(sliders[i],SIGNAL(valueChanged(int)),this,SLOT(sliderChanged(int))); 00137 } 00138 00139 void MultithreadedSliderWidget::valueChanged() 00140 { 00141 if (sliders.isEmpty()) return; 00142 00143 double range,x; 00144 bool ok; 00145 00146 for (int i=0; i < sliders.size(); ++i) 00147 if (sliders[i]) 00148 disconnect(sliders[i],SIGNAL(valueChanged(int)),this,SLOT(sliderChanged(int))); 00149 00150 for (int i=0; i < valueline.size() && i < sliders.size() && i < max.size() && i < min.size(); ++i) 00151 if (sliders[i]) 00152 { 00153 x = valueline[i]->text().toDouble(&ok); 00154 if (ok) 00155 { 00156 if (x > max[i]) 00157 { 00158 max[i] = x; 00159 maxline[i]->setText(QString::number(max[i])); 00160 } 00161 if (x < min[i]) 00162 { 00163 min[i] = x; 00164 minline[i]->setText(QString::number(min[i])); 00165 } 00166 range = (max[i]-min[i]); 00167 values.value(i,0) = x; 00168 sliders[i]->setValue((int)((x - min[i]) * 100.0/range)); 00169 } 00170 else 00171 { 00172 valueline[i]->setText(QString::number(values.value(i,0))); 00173 } 00174 } 00175 00176 for (int i=0; i < sliders.size(); ++i) 00177 if (sliders[i]) 00178 connect(sliders[i],SIGNAL(valueChanged(int)),this,SLOT(sliderChanged(int))); 00179 00180 emit valuesChanged(values); 00181 00182 if (cthread) 00183 { 00184 cthread->setArg(values); 00185 00186 if (cthread->isRunning()) 00187 { 00188 if (mainWindow && mainWindow->console()) 00189 mainWindow->console()->message(tr("Previous run has not finished yet")); 00190 return; 00191 //cthread->terminate(); 00192 } 00193 cthread->start(); 00194 } 00195 } 00196 00197 void MultithreadedSliderWidget::sliderChanged(int) 00198 { 00199 if (sliders.isEmpty()) return; 00200 00201 double range; 00202 00203 for (int i=0; i < valueline.size() && i < sliders.size() && i < max.size() && i < min.size(); ++i) 00204 if (sliders[i]) 00205 { 00206 range = (max[i]-min[i]); 00207 values.value(i,0) = min[i] + (range * sliders[i]->value())/100.0; 00208 valueline[i]->setText(QString::number(values.value(i,0)).left(6)); 00209 } 00210 valueChanged(); 00211 } 00212 00213 void MultithreadedSliderWidget::setSliders(const QStringList& options, const QList<double>& minValues, const QList<double>& maxValues) 00214 { 00215 QSlider * slider; 00216 QLabel * label; 00217 QLineEdit * line; 00218 00219 sliders.clear(); 00220 labels.clear(); 00221 min.clear(); 00222 max.clear(); 00223 minline.clear(); 00224 maxline.clear(); 00225 valueline.clear(); 00226 values.resize(options.size(),1); 00227 //values.setRowNames(options); 00228 values.setColumnNames(QStringList() << "value"); 00229 00230 if (this->layout()) 00231 delete (layout()); 00232 00233 //create tab widget if names contain "::" 00234 bool createTabs = false; 00235 for (int i=0; i < options.size(); ++i) 00236 if (options[i].contains("::")) 00237 { 00238 createTabs = true; 00239 break; 00240 } 00241 00242 QHBoxLayout* layout = 0; 00243 QVBoxLayout * slidersLayout = 0; 00244 00245 QHash< QString, QVBoxLayout * > slidersLayoutsHash; //only if using multiple tabs 00246 00247 if (createTabs) 00248 { 00249 for (int i=0; i < options.size(); ++i) 00250 { 00251 QString tabname; 00252 if (options[i].contains("::")) 00253 { 00254 QStringList words = options[i].split("::"); 00255 tabname = words[0]; 00256 } 00257 if (tabname.isNull() || tabname.isEmpty()) 00258 tabname = tr("misc."); 00259 if (!slidersLayoutsHash.contains(tabname)) 00260 { 00261 layout = new QHBoxLayout; 00262 layout->addWidget(new QLabel(tr("name"))); 00263 layout->addWidget(new QLabel(tr(""))); 00264 layout->addWidget(new QLabel(tr("value"))); 00265 layout->addWidget(new QLabel(tr("min"))); 00266 layout->addWidget(new QLabel(tr("max"))); 00267 00268 slidersLayout = new QVBoxLayout; 00269 QWidget * widget = new QWidget; 00270 widget->setLayout(layout); 00271 slidersLayout->addWidget(widget); 00272 slidersLayoutsHash[ tabname ] = slidersLayout; 00273 } 00274 } 00275 } 00276 else 00277 { 00278 layout = new QHBoxLayout; 00279 layout->addWidget(new QLabel(tr("name"))); 00280 layout->addWidget(new QLabel(tr(""))); 00281 layout->addWidget(new QLabel(tr("value"))); 00282 layout->addWidget(new QLabel(tr("min"))); 00283 layout->addWidget(new QLabel(tr("max"))); 00284 00285 slidersLayout = new QVBoxLayout; 00286 QWidget * widget = new QWidget; 00287 widget->setLayout(layout); 00288 slidersLayout->addWidget(widget); 00289 } 00290 00291 for (int i=0; i < options.size() && i < minValues.size() && i < maxValues.size(); ++i) 00292 { 00293 QString tabname, labelname; 00294 if (createTabs) 00295 { 00296 if (options[i].contains("::")) 00297 { 00298 QStringList words = options[i].split("::"); 00299 tabname = words[0]; 00300 labelname = words[1]; 00301 } 00302 if (tabname.isNull() || tabname.isEmpty()) 00303 tabname = tr("misc."); 00304 slidersLayout = slidersLayoutsHash[ tabname ]; 00305 } 00306 else 00307 { 00308 labelname = options[i]; 00309 } 00310 00311 values.setRowName(i, labelname); 00312 layout = new QHBoxLayout; 00313 label = new QLabel(labelname); 00314 //label->setMaximumWidth(options[i].size() * 3); 00315 layout->addWidget(label); 00316 labels << label; 00317 00318 slider = new QSlider; 00319 slider->setOrientation(orientation); 00320 slider->setRange(0,100); 00321 slider->setValue(50); 00322 slider->setMinimumWidth(100); 00323 layout->addWidget(slider,5); 00324 sliders << slider; 00325 slider->setTracking(false); 00326 connect(slider,SIGNAL(valueChanged(int)),this,SLOT(sliderChanged(int))); 00327 00328 values.value(i,0) = (maxValues[i] + minValues[i])/2.0; 00329 00330 line = new QLineEdit; 00331 line->setText(QString::number(values.value(i,0) )); 00332 line->setMaximumWidth(80); 00333 layout->addWidget(line); 00334 valueline << line; 00335 connect(line,SIGNAL(editingFinished()),this,SLOT(valueChanged())); 00336 00337 line = new QLineEdit; 00338 line->setText(QString::number(minValues[i])); 00339 line->setMaximumWidth(80); 00340 layout->addWidget(line); 00341 minline << line; 00342 min << minValues[i]; 00343 connect(line,SIGNAL(editingFinished()),this,SLOT(minmaxChanged())); 00344 00345 line = new QLineEdit; 00346 line->setMaximumWidth(80); 00347 layout->addWidget(line); 00348 maxline << line; 00349 if (maxValues[i] == minValues[i]) 00350 { 00351 if (minValues[i] == 0) 00352 { 00353 line->setText(QString::number(maxValues[i]+1.0)); 00354 max << maxValues[i] + 1.0; 00355 } 00356 else 00357 { 00358 line->setText(QString::number(maxValues[i]*2)); 00359 max << maxValues[i]*2; 00360 } 00361 } 00362 else 00363 { 00364 line->setText(QString::number(maxValues[i])); 00365 max << maxValues[i]; 00366 } 00367 connect(line,SIGNAL(editingFinished()),this,SLOT(minmaxChanged())); 00368 00369 QWidget * widget = new QWidget; 00370 widget->setLayout(layout); 00371 slidersLayout->addWidget(widget); 00372 sliderWidgets[ labelname ] = widget; 00373 } 00374 00375 QWidget * centralWidget = 0; 00376 00377 if (createTabs) 00378 { 00379 QTabWidget * tabWidget = new QTabWidget; 00380 QStringList keys = slidersLayoutsHash.keys(); 00381 for (int i=0; i < keys.size(); ++i) 00382 { 00383 slidersLayout = slidersLayoutsHash[ keys[i] ]; 00384 QWidget * slidersWidget = new QWidget; 00385 slidersWidget->setLayout(slidersLayout); 00386 QScrollArea * scrollArea = new QScrollArea; 00387 scrollArea->setWidget(slidersWidget); 00388 scrollArea->setWidgetResizable(true); 00389 tabWidget->addTab(scrollArea, keys[i]); 00390 } 00391 centralWidget = tabWidget; 00392 } 00393 else 00394 { 00395 QWidget * slidersWidget = new QWidget; 00396 slidersWidget->setLayout(slidersLayout); 00397 QScrollArea * scrollArea = new QScrollArea; 00398 scrollArea->setWidget(slidersWidget); 00399 scrollArea->setWidgetResizable(true); 00400 centralWidget = scrollArea; 00401 } 00402 00403 QVBoxLayout * mainlayout = new QVBoxLayout; 00404 //search box 00405 QHBoxLayout * searchLayout = new QHBoxLayout; 00406 QLineEdit * searchLine = new QLineEdit; 00407 searchLine->setText(tr("")); 00408 searchLayout->addStretch(2); 00409 searchLayout->addWidget(new QLabel(tr("Search")), 0); 00410 searchLayout->addWidget(searchLine, 1); 00411 connect(searchLine,SIGNAL(textEdited ( const QString &)),this,SLOT(setVisibleSliders(const QString&))); 00412 00413 //cancel and save buttons 00414 QHBoxLayout * buttonLayout = new QHBoxLayout; 00415 QPushButton * closeButton = new QPushButton(tr("&Close")); 00416 QPushButton * saveValues = new QPushButton(tr("&Save values")); 00417 buttonLayout->addStretch(1); 00418 buttonLayout->addWidget(saveValues); 00419 buttonLayout->addWidget(closeButton); 00420 buttonLayout->addStretch(1); 00421 00422 //main layout 00423 mainlayout->addLayout(searchLayout,0); 00424 mainlayout->addWidget(centralWidget,1); 00425 mainlayout->addLayout(buttonLayout,0); 00426 connect(closeButton,SIGNAL(pressed()),this,SLOT(close())); 00427 connect(saveValues,SIGNAL(pressed()),this,SLOT(saveValues())); 00428 setLayout(mainlayout); 00429 00430 valueChanged(); 00431 } 00432 00433 DataTable<qreal> MultithreadedSliderWidget::data() const 00434 { 00435 return values; 00436 } 00437 00438 void MultithreadedSliderWidget::setDefaultDataTable(const QString& s) 00439 { 00440 defaultDataTable = s; 00441 } 00442 00443 void MultithreadedSliderWidget::saveValues() 00444 { 00445 NetworkHandle * network = mainWindow->currentNetwork(); 00446 if (!network) 00447 { 00448 mainWindow->statusBar()->showMessage(tr("No model to update")); 00449 return; 00450 } 00451 00452 SymbolsTable & symbols = network->symbolsTable; 00453 QString s; 00454 qreal d; 00455 bool ok; 00456 QList<NumericalDataTable*> newTables, oldTables; 00457 NumericalDataTable * newTable, * oldTable; 00458 QPair<ItemHandle*,QString> pair; 00459 int k; 00460 for (int i=0; i < labels.size() && i < valueline.size(); ++i) 00461 if (labels[i] && valueline[i]) 00462 { 00463 s = labels[i]->text(); 00464 d = valueline[i]->text().toDouble(&ok); 00465 00466 if (!ok) continue; 00467 00468 if (symbols.uniqueDataWithDot.contains(s)) 00469 { 00470 pair = symbols.uniqueDataWithDot.value(s); 00471 if (pair.first && pair.first->hasNumericalData(pair.second)) 00472 { 00473 oldTable = &(pair.first->numericalDataTable(pair.second)); 00474 s.remove(pair.first->fullName() + tr(".")); 00475 if (oldTable->hasRow(s) && oldTable->value(s,0) != d) 00476 { 00477 k = oldTables.indexOf(oldTable); 00478 if (k > -1) 00479 newTable = newTables[k]; 00480 else 00481 { 00482 newTable = new NumericalDataTable(*oldTable); 00483 oldTables << oldTable; 00484 newTables << newTable; 00485 } 00486 newTable->value(s,0) = d; 00487 } 00488 } 00489 } 00490 else 00491 { 00492 s.replace(tr("."),tr("_")); 00493 if (symbols.uniqueDataWithUnderscore.contains(s)) 00494 { 00495 pair = symbols.uniqueDataWithUnderscore.value(s); 00496 if (pair.first && pair.first->hasNumericalData(pair.second)) 00497 { 00498 oldTable = &(pair.first->numericalDataTable(pair.second)); 00499 s.remove(pair.first->fullName(tr("_")) + tr("_")); 00500 if (oldTable->hasRow(s) && oldTable->value(s,0) != d) 00501 { 00502 k = oldTables.indexOf(oldTable); 00503 if (k > -1) 00504 newTable = newTables[k]; 00505 else 00506 { 00507 newTable = new NumericalDataTable(*oldTable); 00508 oldTables << oldTable; 00509 newTables << newTable; 00510 } 00511 newTable->value(s,0) = d; 00512 } 00513 } 00514 } 00515 else 00516 if (!defaultDataTable.isNull() && 00517 !defaultDataTable.isEmpty() && 00518 symbols.uniqueHandlesWithUnderscore.contains(s)) 00519 { 00520 ItemHandle * h = symbols.uniqueHandlesWithUnderscore[s]; 00521 if (h->hasNumericalData(defaultDataTable)) 00522 { 00523 oldTable = &(h->numericalDataTable(defaultDataTable)); 00524 if (oldTable->value(0,0) != d) 00525 { 00526 k = oldTables.indexOf(oldTable); 00527 if (k > -1) 00528 newTable = newTables[k]; 00529 else 00530 { 00531 newTable = new NumericalDataTable(*oldTable); 00532 oldTables << oldTable; 00533 newTables << newTable; 00534 } 00535 newTable->value(0,0) = d; 00536 } 00537 } 00538 } 00539 } 00540 } 00541 00542 if (!newTables.isEmpty()) 00543 { 00544 network->push(new ChangeNumericalDataCommand(tr("Updated from slider"), oldTables, newTables)); 00545 for (int i=0; i < newTables.size(); ++i) 00546 delete newTables[i]; 00547 } 00548 } 00549 } 00550 00551