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