1 #include "pch.h"
2 #include "MainWindow.hpp"
3 #include "ui_mainwindow.h"
4
5 #include <iostream>
6
7 #include <QCloseEvent>
8 #include <QTimer>
9
10 #include <QInputDialog>
11 #include <QMessageBox>
12
13 #include "Editor.hpp"
14 #include "ColoredTabWidget.hpp"
15 #include "AddPropertyDialog.hpp"
16
MainWindow(QWidget * parent)17 sh::MainWindow::MainWindow(QWidget *parent)
18 : QMainWindow(parent)
19 , ui(new Ui::MainWindow)
20 , mRequestShowWindow(false)
21 , mRequestExit(false)
22 , mIgnoreGlobalSettingChange(false)
23 , mIgnoreConfigurationChange(false)
24 , mIgnoreMaterialChange(false)
25 , mIgnoreMaterialPropertyChange(false)
26 {
27 ui->setupUi(this);
28
29 QTimer *timer = new QTimer(this);
30 connect(timer, SIGNAL(timeout()), this, SLOT(onIdle()));
31 timer->start(50);
32
33 QList<int> sizes;
34 sizes << 250;
35 sizes << 550;
36 ui->splitter->setSizes(sizes);
37
38 mMaterialModel = new QStringListModel(this);
39
40 mMaterialProxyModel = new QSortFilterProxyModel(this);
41 mMaterialProxyModel->setSourceModel(mMaterialModel);
42 mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
43 mMaterialProxyModel->setDynamicSortFilter(true);
44 mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
45
46 ui->materialList->setModel(mMaterialProxyModel);
47 ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection);
48 ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers);
49 ui->materialList->setAlternatingRowColors(true);
50
51 connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
52 this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex)));
53
54 mMaterialPropertyModel = new QStandardItemModel(0, 2, this);
55 mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
56 mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
57 connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)),
58 this, SLOT(onMaterialPropertyChanged(QStandardItem*)));
59
60 mMaterialSortModel = new PropertySortModel(this);
61 mMaterialSortModel->setSourceModel(mMaterialPropertyModel);
62 mMaterialSortModel->setDynamicSortFilter(true);
63 mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
64
65 ui->materialView->setModel(mMaterialSortModel);
66 ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu);
67 ui->materialView->setAlternatingRowColors(true);
68 ui->materialView->setSortingEnabled(true);
69 connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)),
70 this, SLOT(onContextMenuRequested(QPoint)));
71
72 mGlobalSettingsModel = new QStandardItemModel(0, 2, this);
73 mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
74 mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
75 connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)),
76 this, SLOT(onGlobalSettingChanged(QStandardItem*)));
77
78 ui->globalSettingsView->setModel(mGlobalSettingsModel);
79 ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
80 ui->globalSettingsView->verticalHeader()->hide();
81 ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
82 ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection);
83
84 ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection);
85 ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers);
86 connect(ui->configurationList, SIGNAL(currentTextChanged(QString)),
87 this, SLOT(onConfigurationSelectionChanged(QString)));
88
89 mConfigurationModel = new QStandardItemModel(0, 2, this);
90 mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
91 mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
92 connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)),
93 this, SLOT(onConfigurationChanged(QStandardItem*)));
94
95 ui->configurationView->setModel(mConfigurationModel);
96 ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
97 ui->configurationView->verticalHeader()->hide();
98 ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
99 ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection);
100 }
101
~MainWindow()102 sh::MainWindow::~MainWindow()
103 {
104 delete ui;
105 }
106
closeEvent(QCloseEvent * event)107 void sh::MainWindow::closeEvent(QCloseEvent *event)
108 {
109 this->hide();
110 event->ignore();
111 }
112
onIdle()113 void sh::MainWindow::onIdle()
114 {
115 if (mRequestShowWindow)
116 {
117 mRequestShowWindow = false;
118 show();
119 }
120
121 if (mRequestExit)
122 {
123 QApplication::exit();
124 return;
125 }
126
127 boost::mutex::scoped_lock lock(mSync->mUpdateMutex);
128
129
130 mIgnoreMaterialChange = true;
131 QString selected;
132
133 QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
134 if (selectedIndex.isValid())
135 selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString();
136
137 QStringList list;
138
139 for (std::vector<std::string>::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it)
140 {
141 list.push_back(QString::fromStdString(*it));
142 }
143
144 if (mMaterialModel->stringList() != list)
145 {
146 mMaterialModel->setStringList(list);
147
148 // quick hack to keep our selection when the model has changed
149 if (!selected.isEmpty())
150 for (int i=0; i<mMaterialModel->rowCount(); ++i)
151 {
152 const QModelIndex& index = mMaterialModel->index(i,0);
153 if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected)
154 {
155 ui->materialList->setCurrentIndex(index);
156 break;
157 }
158 }
159 }
160 mIgnoreMaterialChange = false;
161
162 mIgnoreGlobalSettingChange = true;
163 for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
164 it != mState.mGlobalSettingsMap.end(); ++it)
165 {
166 QList<QStandardItem *> list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first));
167 if (!list.empty()) // item was already there
168 {
169 // if it changed, set the value column
170 if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString()
171 != QString::fromStdString(it->second))
172 {
173 mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second)));
174 }
175 }
176 else // item wasn't there; insert new row
177 {
178 QList<QStandardItem*> toAdd;
179 QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
180 name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
181 QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
182 toAdd.push_back(name);
183 toAdd.push_back(value);
184 mGlobalSettingsModel->appendRow(toAdd);
185 }
186 }
187 mIgnoreGlobalSettingChange = false;
188
189
190 mIgnoreConfigurationChange = true;
191 QList<QListWidgetItem*> selected_ = ui->configurationList->selectedItems();
192 QString selectedStr;
193 if (selected_.size())
194 selectedStr = selected_.front()->text();
195
196 ui->configurationList->clear();
197
198 for (std::vector<std::string>::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it)
199 ui->configurationList->addItem(QString::fromStdString(*it));
200
201 if (!selectedStr.isEmpty())
202 for (int i=0; i<ui->configurationList->count(); ++i)
203 {
204 if (ui->configurationList->item(i)->text() == selectedStr)
205 {
206 ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect);
207 }
208 }
209
210 mIgnoreConfigurationChange = false;
211
212 if (!mState.mErrors.empty())
213 {
214 ui->errorLog->append(QString::fromStdString(mState.mErrors));
215 mState.mErrors = "";
216 QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link);
217 ui->tabWidget->tabBar()->setTabTextColor(3, color);
218 }
219
220
221 // process query results
222 boost::mutex::scoped_lock lock2(mSync->mQueryMutex);
223 for (std::vector<Query*>::iterator it = mQueries.begin(); it != mQueries.end();)
224 {
225 if ((*it)->mDone)
226 {
227 if (typeid(**it) == typeid(ConfigurationQuery))
228 buildConfigurationModel(static_cast<ConfigurationQuery*>(*it));
229 else if (typeid(**it) == typeid(MaterialQuery))
230 buildMaterialModel(static_cast<MaterialQuery*>(*it));
231 else if (typeid(**it) == typeid(MaterialPropertyQuery))
232 {
233 MaterialPropertyQuery* q = static_cast<MaterialPropertyQuery*>(*it);
234 mIgnoreMaterialPropertyChange = true;
235 if (getSelectedMaterial().toStdString() == q->mName)
236 {
237 for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
238 {
239 if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName))
240 {
241 mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue));
242 if (mMaterialPropertyModel->item(i,1)->isCheckable())
243 mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true")
244 ? Qt::Checked : Qt::Unchecked);
245 }
246 }
247 }
248 mIgnoreMaterialPropertyChange = false;
249 }
250
251 delete *it;
252 it = mQueries.erase(it);
253 }
254 else
255 ++it;
256 }
257 }
258
onMaterialSelectionChanged(const QModelIndex & current,const QModelIndex & previous)259 void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous)
260 {
261 if (mIgnoreMaterialChange)
262 return;
263
264 QString name = getSelectedMaterial();
265 if (!name.isEmpty())
266 requestQuery(new sh::MaterialQuery(name.toStdString()));
267 }
268
getSelectedMaterial()269 QString sh::MainWindow::getSelectedMaterial()
270 {
271 QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
272 if (!selectedIndex.isValid())
273 return QString("");
274
275 return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
276 }
277
onConfigurationSelectionChanged(const QString & current)278 void sh::MainWindow::onConfigurationSelectionChanged (const QString& current)
279 {
280 if (mIgnoreConfigurationChange)
281 return;
282 requestQuery(new sh::ConfigurationQuery(current.toStdString()));
283 }
284
onGlobalSettingChanged(QStandardItem * item)285 void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item)
286 {
287 if (mIgnoreGlobalSettingChange)
288 return; // we are only interested in changes by the user, not by the backend.
289
290 std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString();
291 std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString();
292
293 queueAction(new sh::ActionChangeGlobalSetting(name, value));
294 }
295
onConfigurationChanged(QStandardItem * item)296 void sh::MainWindow::onConfigurationChanged (QStandardItem* item)
297 {
298 QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
299 if (items.size())
300 {
301 std::string name = items.front()->text().toStdString();
302 std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString();
303 std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString();
304
305 queueAction(new sh::ActionChangeConfiguration(name, key, value));
306
307 requestQuery(new sh::ConfigurationQuery(name));
308 }
309 }
310
on_lineEdit_textEdited(const QString & arg1)311 void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1)
312 {
313 mMaterialProxyModel->setFilterFixedString(arg1);
314 }
315
on_actionSave_triggered()316 void sh::MainWindow::on_actionSave_triggered()
317 {
318 queueAction (new sh::ActionSaveAll());
319 }
320
on_actionNewMaterial_triggered()321 void sh::MainWindow::on_actionNewMaterial_triggered()
322 {
323
324 }
325
on_actionDeleteMaterial_triggered()326 void sh::MainWindow::on_actionDeleteMaterial_triggered()
327 {
328 QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
329 QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
330
331 queueAction (new sh::ActionDeleteMaterial(name.toStdString()));
332 }
333
queueAction(Action * action)334 void sh::MainWindow::queueAction(Action* action)
335 {
336 boost::mutex::scoped_lock lock(mSync->mActionMutex);
337 mActionQueue.push(action);
338 }
339
requestQuery(Query * query)340 void sh::MainWindow::requestQuery(Query *query)
341 {
342 boost::mutex::scoped_lock lock(mSync->mActionMutex);
343 mQueries.push_back(query);
344 }
345
on_actionQuit_triggered()346 void sh::MainWindow::on_actionQuit_triggered()
347 {
348 hide();
349 }
350
on_actionNewConfiguration_triggered()351 void sh::MainWindow::on_actionNewConfiguration_triggered()
352 {
353 QInputDialog dialog(this);
354
355 QString text = QInputDialog::getText(this, tr("New Configuration"),
356 tr("Configuration name:"));
357
358 if (!text.isEmpty())
359 {
360 queueAction(new ActionCreateConfiguration(text.toStdString()));
361 }
362 }
363
on_actionDeleteConfiguration_triggered()364 void sh::MainWindow::on_actionDeleteConfiguration_triggered()
365 {
366 QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
367 if (items.size())
368 queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString()));
369 }
370
on_actionDeleteConfigurationProperty_triggered()371 void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered()
372 {
373 QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
374 if (items.empty())
375 return;
376 std::string configurationName = items.front()->text().toStdString();
377
378 QModelIndex current = ui->configurationView->currentIndex();
379 if (!current.isValid())
380 return;
381
382 std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString();
383
384 queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName));
385 requestQuery(new sh::ConfigurationQuery(configurationName));
386 }
387
on_actionCloneMaterial_triggered()388 void sh::MainWindow::on_actionCloneMaterial_triggered()
389 {
390 QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
391 QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
392 if (name.isEmpty())
393 return;
394
395 QInputDialog dialog(this);
396
397 QString text = QInputDialog::getText(this, tr("Clone material"),
398 tr("Name:"));
399
400 if (!text.isEmpty())
401 {
402 queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString()));
403 }
404 }
405
onContextMenuRequested(const QPoint & point)406 void sh::MainWindow::onContextMenuRequested(const QPoint &point)
407 {
408 QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point);
409
410 QMenu menu;
411
412 QList <QAction*> actions;
413 actions.push_back(ui->actionNewProperty);
414 actions.push_back(ui->actionDeleteProperty);
415 actions.push_back(ui->actionCreatePass);
416 actions.push_back(ui->actionCreateTextureUnit);
417 menu.addActions(actions);
418
419 menu.exec(globalPos);
420 }
421
getContext(QModelIndex index,int * passIndex,int * textureIndex,bool * isInPass,bool * isInTextureUnit)422 void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit)
423 {
424 if (passIndex)
425 {
426 *passIndex = 0;
427 if (isInPass)
428 *isInPass = false;
429 QModelIndex passModelIndex = index;
430 // go up until we find the pass item.
431 while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid())
432 passModelIndex = passModelIndex.parent();
433
434 if (passModelIndex.isValid())
435 {
436 if (passModelIndex.column() != 0)
437 passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0);
438 for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
439 {
440 if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
441 {
442 if (mMaterialPropertyModel->index(i, 0) == passModelIndex)
443 {
444 if (isInPass)
445 *isInPass = true;
446 break;
447 }
448 ++(*passIndex);
449 }
450 }
451 }
452 }
453 if (textureIndex)
454 {
455 *textureIndex = 0;
456 if (isInTextureUnit)
457 *isInTextureUnit = false;
458 QModelIndex texModelIndex = index;
459 // go up until we find the texture_unit item.
460 while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid())
461 texModelIndex = texModelIndex.parent();
462 if (texModelIndex.isValid())
463 {
464 if (texModelIndex.column() != 0)
465 texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0);
466 for (int i=0; i<mMaterialPropertyModel->rowCount(texModelIndex.parent()); ++i)
467 {
468 if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit"))
469 {
470 if (texModelIndex.parent().child(i, 0) == texModelIndex)
471 {
472 if (isInTextureUnit)
473 *isInTextureUnit = true;
474 break;
475 }
476 ++(*textureIndex);
477 }
478 }
479 }
480 }
481 }
482
getPropertyKey(QModelIndex index)483 std::string sh::MainWindow::getPropertyKey(QModelIndex index)
484 {
485 if (!index.parent().isValid())
486 return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString();
487 else
488 return index.parent().child(index.row(), 0).data().toString().toStdString();
489 }
490
getPropertyValue(QModelIndex index)491 std::string sh::MainWindow::getPropertyValue(QModelIndex index)
492 {
493 if (!index.parent().isValid())
494 return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString();
495 else
496 return index.parent().child(index.row(), 1).data().toString().toStdString();
497 }
498
onMaterialPropertyChanged(QStandardItem * item)499 void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item)
500 {
501 if (mIgnoreMaterialPropertyChange)
502 return;
503
504 QString material = getSelectedMaterial();
505 if (material.isEmpty())
506 return;
507
508 // handle checkboxes being checked/unchecked
509 std::string value = getPropertyValue(item->index());
510 if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean)
511 {
512 if (item->checkState() == Qt::Checked && value != "true")
513 value = "true";
514 else if (item->checkState() == Qt::Unchecked && value == "true")
515 value = "false";
516 item->setText(QString::fromStdString(value));
517 }
518
519 // handle inherited properties being changed, i.e. overridden by the current (derived) material
520 if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged)
521 {
522 QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText);
523 mIgnoreMaterialPropertyChange = true;
524 mMaterialPropertyModel->item(item->index().row(), 0)
525 ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
526 mMaterialPropertyModel->item(item->index().row(), 0)
527 ->setData(normalColor, Qt::ForegroundRole);
528 mMaterialPropertyModel->item(item->index().row(), 1)
529 ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
530 mMaterialPropertyModel->item(item->index().row(), 1)
531 ->setData(normalColor, Qt::ForegroundRole);
532 mIgnoreMaterialPropertyChange = false;
533
534 ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index()));
535 }
536
537 if (!item->index().parent().isValid())
538 {
539 // top level material property
540 queueAction(new ActionSetMaterialProperty(
541 material.toStdString(), getPropertyKey(item->index()), value));
542 }
543 else if (getPropertyKey(item->index()) == "texture_unit")
544 {
545 // texture unit name changed
546 int passIndex, textureIndex;
547 getContext(item->index(), &passIndex, &textureIndex);
548 std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl;
549
550 queueAction(new ActionChangeTextureUnitName(
551 material.toStdString(), passIndex, textureIndex, value));
552
553 }
554 else if (item->index().parent().data().toString() == "pass")
555 {
556 // pass property
557 int passIndex;
558 getContext(item->index(), &passIndex, NULL);
559 /// \todo if shaders are changed, check that the material provides all properties needed by the shader
560 queueAction(new ActionSetPassProperty(
561 material.toStdString(), passIndex, getPropertyKey(item->index()), value));
562 }
563 else if (item->index().parent().data().toString() == "shader_properties")
564 {
565 // shader property
566 int passIndex;
567 getContext(item->index(), &passIndex, NULL);
568 queueAction(new ActionSetShaderProperty(
569 material.toStdString(), passIndex, getPropertyKey(item->index()), value));
570 }
571 else if (item->index().parent().data().toString() == "texture_unit")
572 {
573 // texture property
574 int passIndex, textureIndex;
575 getContext(item->index(), &passIndex, &textureIndex);
576 queueAction(new ActionSetTextureProperty(
577 material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value));
578 }
579 }
580
buildMaterialModel(MaterialQuery * data)581 void sh::MainWindow::buildMaterialModel(MaterialQuery *data)
582 {
583 mMaterialPropertyModel->clear();
584
585 mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
586 mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
587
588 for (std::map<std::string, MaterialProperty>::const_iterator it = data->mProperties.begin();
589 it != data->mProperties.end(); ++it)
590 {
591 addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second);
592 }
593
594 for (std::vector<PassInfo>::iterator it = data->mPasses.begin();
595 it != data->mPasses.end(); ++it)
596 {
597 QStandardItem* passItem = new QStandardItem (QString("pass"));
598 passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable);
599 passItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
600
601 if (it->mShaderProperties.size())
602 {
603 QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties"));
604 shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable);
605 shaderPropertiesItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
606
607 for (std::map<std::string, MaterialProperty>::iterator pit = it->mShaderProperties.begin();
608 pit != it->mShaderProperties.end(); ++pit)
609 {
610 addProperty(shaderPropertiesItem, pit->first, pit->second);
611 }
612 passItem->appendRow(shaderPropertiesItem);
613 }
614
615 for (std::map<std::string, MaterialProperty>::iterator pit = it->mProperties.begin();
616 pit != it->mProperties.end(); ++pit)
617 {
618 addProperty(passItem, pit->first, pit->second);
619 }
620
621 for (std::vector<TextureUnitInfo>::iterator tIt = it->mTextureUnits.begin();
622 tIt != it->mTextureUnits.end(); ++tIt)
623 {
624 QStandardItem* unitItem = new QStandardItem (QString("texture_unit"));
625 unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable);
626 unitItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
627 QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName));
628 nameItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
629
630 QList<QStandardItem*> texUnit;
631 texUnit << unitItem << nameItem;
632
633 for (std::map<std::string, MaterialProperty>::iterator pit = tIt->mProperties.begin();
634 pit != tIt->mProperties.end(); ++pit)
635 {
636 addProperty(unitItem, pit->first, pit->second);
637 }
638
639 passItem->appendRow(texUnit);
640 }
641
642 QList<QStandardItem*> toAdd;
643 toAdd << passItem;
644 toAdd << new QStandardItem(QString(""));
645 mMaterialPropertyModel->appendRow(toAdd);
646 }
647
648 ui->materialView->expandAll();
649 ui->materialView->resizeColumnToContents(0);
650 ui->materialView->resizeColumnToContents(1);
651 }
652
addProperty(QStandardItem * parent,const std::string & key,MaterialProperty value,bool scrollTo)653 void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo)
654 {
655 QList<QStandardItem*> toAdd;
656 QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key));
657 keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
658 keyItem->setData(QVariant(value.mType), Qt::UserRole);
659 keyItem->setData(QVariant(value.mSource), Qt::UserRole+1);
660 toAdd.push_back(keyItem);
661
662 QStandardItem* valueItem = NULL;
663 if (value.mSource != MaterialProperty::None)
664 {
665 valueItem = new QStandardItem(QString::fromStdString(value.mValue));
666 valueItem->setData(QVariant(value.mType), Qt::UserRole);
667 valueItem->setData(QVariant(value.mSource), Qt::UserRole+1);
668 toAdd.push_back(valueItem);
669 }
670
671
672 if (value.mSource == MaterialProperty::Inherited_Unchanged)
673 {
674 QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
675 keyItem->setData(color, Qt::ForegroundRole);
676 if (valueItem)
677 valueItem->setData(color, Qt::ForegroundRole);
678 }
679 if (value.mType == MaterialProperty::Boolean && valueItem)
680 {
681 valueItem->setCheckable(true);
682 valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked);
683 }
684
685 parent->appendRow(toAdd);
686
687 if (scrollTo)
688 ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index()));
689 }
690
buildConfigurationModel(ConfigurationQuery * data)691 void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data)
692 {
693 while (mConfigurationModel->rowCount())
694 mConfigurationModel->removeRow(0);
695 for (std::map<std::string, std::string>::iterator it = data->mProperties.begin();
696 it != data->mProperties.end(); ++it)
697 {
698 QList<QStandardItem*> toAdd;
699 QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
700 name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
701 QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
702 toAdd.push_back(name);
703 toAdd.push_back(value);
704 mConfigurationModel->appendRow(toAdd);
705 }
706
707 // add items that are in global settings, but not in this configuration (with a "inactive" color)
708 for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
709 it != mState.mGlobalSettingsMap.end(); ++it)
710 {
711 if (data->mProperties.find(it->first) == data->mProperties.end())
712 {
713 QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
714 QList<QStandardItem*> toAdd;
715 QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
716 name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
717 name->setData(color, Qt::ForegroundRole);
718 QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
719 value->setData(color, Qt::ForegroundRole);
720 toAdd.push_back(name);
721 toAdd.push_back(value);
722 mConfigurationModel->appendRow(toAdd);
723 }
724 }
725 }
726
on_actionCreatePass_triggered()727 void sh::MainWindow::on_actionCreatePass_triggered()
728 {
729 QString material = getSelectedMaterial();
730 if (!material.isEmpty())
731 {
732 addProperty(mMaterialPropertyModel->invisibleRootItem(),
733 "pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true);
734
735 queueAction (new ActionCreatePass(material.toStdString()));
736 }
737 }
738
on_actionDeleteProperty_triggered()739 void sh::MainWindow::on_actionDeleteProperty_triggered()
740 {
741 QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
742 QString material = getSelectedMaterial();
743 if (material.isEmpty())
744 return;
745
746 mIgnoreMaterialPropertyChange = true;
747
748 if (getPropertyKey(selectedIndex) == "pass")
749 {
750 // delete whole pass
751 int passIndex;
752 getContext(selectedIndex, &passIndex, NULL);
753 if (passIndex == 0)
754 {
755 QMessageBox msgBox;
756 msgBox.setText("The first pass can not be deleted.");
757 msgBox.exec();
758 }
759 else
760 {
761 queueAction(new ActionDeletePass(material.toStdString(), passIndex));
762 mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
763 }
764 }
765 else if (getPropertyKey(selectedIndex) == "texture_unit")
766 {
767 // delete whole texture unit
768 int passIndex, textureIndex;
769 getContext(selectedIndex, &passIndex, &textureIndex);
770 queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex));
771 mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
772 }
773 else if (!selectedIndex.parent().isValid())
774 {
775 // top level material property
776 MaterialProperty::Source source = static_cast<MaterialProperty::Source>(
777 mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt());
778 if (source == MaterialProperty::Inherited_Unchanged)
779 {
780 QMessageBox msgBox;
781 msgBox.setText("Inherited properties can not be deleted.");
782 msgBox.exec();
783 }
784 else
785 {
786 queueAction(new ActionDeleteMaterialProperty(
787 material.toStdString(), getPropertyKey(selectedIndex)));
788 std::cout << "source is " << source << std::endl;
789 if (source == MaterialProperty::Inherited_Changed)
790 {
791 QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText);
792 mMaterialPropertyModel->item(selectedIndex.row(), 0)
793 ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
794 mMaterialPropertyModel->item(selectedIndex.row(), 0)
795 ->setData(inactiveColor, Qt::ForegroundRole);
796 mMaterialPropertyModel->item(selectedIndex.row(), 1)
797 ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
798 mMaterialPropertyModel->item(selectedIndex.row(), 1)
799 ->setData(inactiveColor, Qt::ForegroundRole);
800
801 // make sure to update the property's value
802 requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex)));
803 }
804 else
805 mMaterialPropertyModel->removeRow(selectedIndex.row());
806 }
807 }
808 else if (selectedIndex.parent().data().toString() == "pass")
809 {
810 // pass property
811 int passIndex;
812 getContext(selectedIndex, &passIndex, NULL);
813 queueAction(new ActionDeletePassProperty(
814 material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
815 mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
816 }
817 else if (selectedIndex.parent().data().toString() == "shader_properties")
818 {
819 // shader property
820 int passIndex;
821 getContext(selectedIndex, &passIndex, NULL);
822 queueAction(new ActionDeleteShaderProperty(
823 material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
824 mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
825 }
826 else if (selectedIndex.parent().data().toString() == "texture_unit")
827 {
828 // texture property
829 int passIndex, textureIndex;
830 getContext(selectedIndex, &passIndex, &textureIndex);
831 queueAction(new ActionDeleteTextureProperty(
832 material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex)));
833 mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
834 }
835 mIgnoreMaterialPropertyChange = false;
836 }
837
on_actionNewProperty_triggered()838 void sh::MainWindow::on_actionNewProperty_triggered()
839 {
840 QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
841 QString material = getSelectedMaterial();
842 if (material.isEmpty())
843 return;
844
845 AddPropertyDialog* dialog = new AddPropertyDialog(this);
846 dialog->exec();
847 QString propertyName = dialog->mName;
848 QString defaultValue = "";
849
850 /// \todo check if this property name exists already
851
852 if (!propertyName.isEmpty())
853 {
854 int passIndex, textureIndex;
855 bool isInPass, isInTextureUnit;
856 getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit);
857
858 QList<QStandardItem*> items;
859 QStandardItem* keyItem = new QStandardItem(propertyName);
860 keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
861 items << keyItem;
862 items << new QStandardItem(defaultValue);
863
864 // figure out which item the new property should be a child of
865 QModelIndex parentIndex = selectedIndex;
866 if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object)
867 parentIndex = selectedIndex.parent();
868 QStandardItem* parentItem;
869 if (!parentIndex.isValid())
870 parentItem = mMaterialPropertyModel->invisibleRootItem();
871 else
872 parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex);
873
874 if (isInTextureUnit)
875 {
876 queueAction(new ActionSetTextureProperty(
877 material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString()));
878 }
879 else if (isInPass)
880 {
881 if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties"
882 || selectedIndex.parent().data().toString() == "shader_properties")
883 {
884 queueAction(new ActionSetShaderProperty(
885 material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
886 }
887 else
888 {
889 queueAction(new ActionSetPassProperty(
890 material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
891 }
892 }
893 else
894 {
895 queueAction(new ActionSetMaterialProperty(
896 material.toStdString(), propertyName.toStdString(), defaultValue.toStdString()));
897 }
898
899 addProperty(parentItem, propertyName.toStdString(),
900 MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true);
901
902 /// \todo scroll to newly added property
903 }
904 }
905
on_actionCreateTextureUnit_triggered()906 void sh::MainWindow::on_actionCreateTextureUnit_triggered()
907 {
908 QString material = getSelectedMaterial();
909 if (material.isEmpty())
910 return;
911
912 QInputDialog dialog(this);
913
914 QString text = QInputDialog::getText(this, tr("New texture unit"),
915 tr("Texture unit name (for referencing in shaders):"));
916 if (!text.isEmpty())
917 {
918 QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
919 int passIndex;
920 getContext(selectedIndex, &passIndex, NULL);
921 queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString()));
922
923 // add to model
924 int index = 0;
925 for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
926 {
927 if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
928 {
929 if (index == passIndex)
930 {
931 addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)),
932 "texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true);
933 break;
934 }
935
936 ++index;
937 }
938 }
939 }
940 }
941
on_clearButton_clicked()942 void sh::MainWindow::on_clearButton_clicked()
943 {
944 ui->errorLog->clear();
945 }
946
on_tabWidget_currentChanged(int index)947 void sh::MainWindow::on_tabWidget_currentChanged(int index)
948 {
949 QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText);
950
951 if (index == 3)
952 ui->tabWidget->tabBar()->setTabTextColor(3, color);
953 }
954