diff --git a/extern/shiny/Editor/Actions.cpp b/extern/shiny/Editor/Actions.cpp new file mode 100644 index 0000000000..135e819878 --- /dev/null +++ b/extern/shiny/Editor/Actions.cpp @@ -0,0 +1,195 @@ +#include "Actions.hpp" + +#include "../Main/Factory.hpp" + +namespace sh +{ + + void ActionDeleteMaterial::execute() + { + sh::Factory::getInstance().destroyMaterialInstance(mName); + } + + void ActionCloneMaterial::execute() + { + sh::MaterialInstance* sourceMaterial = sh::Factory::getInstance().getMaterialInstance(mSourceName); + std::string sourceMaterialParent = static_cast(sourceMaterial->getParent())->getName(); + sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance( + mDestName, sourceMaterialParent); + sourceMaterial->copyAll(material, sourceMaterial, false); + + material->setSourceFile(sourceMaterial->getSourceFile()); + } + + void ActionSaveAll::execute() + { + sh::Factory::getInstance().saveAll(); + } + + void ActionChangeGlobalSetting::execute() + { + sh::Factory::getInstance().setGlobalSetting(mName, mNewValue); + } + + void ActionCreateConfiguration::execute() + { + sh::Configuration newConfiguration; + sh::Factory::getInstance().createConfiguration(mName); + } + + void ActionDeleteConfiguration::execute() + { + sh::Factory::getInstance().destroyConfiguration(mName); + } + + void ActionChangeConfiguration::execute() + { + sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); + c->setProperty(mKey, sh::makeProperty(new sh::StringValue(mValue))); + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeleteConfigurationProperty::execute() + { + sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName); + c->deleteProperty(mKey); + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionSetMaterialProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + m->setProperty(mKey, sh::makeProperty(mValue)); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeleteMaterialProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + m->deleteProperty(mKey); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionCreatePass::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + m->createPass(); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeletePass::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + m->deletePass(mPassIndex); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionSetPassProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + m->getPasses()->at(mPassIndex).setProperty (mKey, sh::makeProperty(mValue)); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeletePassProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + m->getPasses()->at(mPassIndex).deleteProperty(mKey); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionSetShaderProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + m->getPasses()->at(mPassIndex).mShaderProperties.setProperty (mKey, sh::makeProperty(mValue)); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeleteShaderProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + m->getPasses()->at(mPassIndex).mShaderProperties.deleteProperty (mKey); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionSetTextureProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); + m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).setProperty(mKey, sh::makeProperty(mValue)); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeleteTextureProperty::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); + m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).deleteProperty(mKey); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionCreateTextureUnit::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + m->getPasses()->at(mPassIndex).createTextureUnit(mTexUnitName); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionDeleteTextureUnit::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); + + m->getPasses()->at(mPassIndex).mTexUnits.erase(m->getPasses()->at(mPassIndex).mTexUnits.begin() + mTextureIndex); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionMoveTextureUnit::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); + if (!mMoveUp) + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex+1); + + std::vector textures = m->getPasses()->at(mPassIndex).mTexUnits; + if (mMoveUp) + std::swap(textures[mTextureIndex-1], textures[mTextureIndex]); + else + std::swap(textures[mTextureIndex+1], textures[mTextureIndex]); + m->getPasses()->at(mPassIndex).mTexUnits = textures; + + sh::Factory::getInstance().notifyConfigurationChanged(); + } + + void ActionChangeTextureUnitName::execute() + { + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + assert (m->getPasses()->size() > mPassIndex); + assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex); + + m->getPasses()->at(mPassIndex).mTexUnits[mTextureIndex].setName(mTexUnitName); + + sh::Factory::getInstance().notifyConfigurationChanged(); + } +} diff --git a/extern/shiny/Editor/Actions.hpp b/extern/shiny/Editor/Actions.hpp new file mode 100644 index 0000000000..e5cb6df6a5 --- /dev/null +++ b/extern/shiny/Editor/Actions.hpp @@ -0,0 +1,307 @@ +#ifndef SH_ACTIONS_H +#define SH_ACTIONS_H + +#include + +namespace sh +{ + + class Action + { + public: + virtual void execute() = 0; + virtual ~Action(); + }; + + class ActionDeleteMaterial : public Action + { + public: + ActionDeleteMaterial(const std::string& name) + : mName(name) {} + + virtual void execute(); + private: + std::string mName; + }; + + class ActionCloneMaterial : public Action + { + public: + ActionCloneMaterial(const std::string& sourceName, const std::string& destName) + : mSourceName(sourceName), mDestName(destName) {} + + virtual void execute(); + private: + std::string mSourceName; + std::string mDestName; + }; + + class ActionSaveAll : public Action + { + public: + virtual void execute(); + }; + + class ActionChangeGlobalSetting : public Action + { + public: + ActionChangeGlobalSetting(const std::string& name, const std::string& newValue) + : mName(name), mNewValue(newValue) {} + + virtual void execute(); + private: + std::string mName; + std::string mNewValue; + }; + + // configuration + + class ActionCreateConfiguration : public Action + { + public: + ActionCreateConfiguration(const std::string& name) + : mName(name) {} + + virtual void execute(); + private: + std::string mName; + + }; + + class ActionDeleteConfiguration : public Action + { + public: + ActionDeleteConfiguration(const std::string& name) + : mName(name) {} + + virtual void execute(); + private: + std::string mName; + + }; + + class ActionChangeConfiguration : public Action + { + public: + ActionChangeConfiguration (const std::string& name, const std::string& key, const std::string& value) + : mName(name), mKey(key), mValue(value) {} + + virtual void execute(); + private: + std::string mName; + std::string mKey; + std::string mValue; + }; + + class ActionDeleteConfigurationProperty : public Action + { + public: + ActionDeleteConfigurationProperty (const std::string& name, const std::string& key) + : mName(name), mKey(key) {} + + virtual void execute(); + private: + std::string mName; + std::string mKey; + }; + + // material + + class ActionSetMaterialProperty : public Action + { + public: + ActionSetMaterialProperty (const std::string& name, const std::string& key, const std::string& value) + : mName(name), mKey(key), mValue(value) {} + + virtual void execute(); + private: + std::string mName; + std::string mKey; + std::string mValue; + }; + + class ActionDeleteMaterialProperty : public Action + { + public: + ActionDeleteMaterialProperty (const std::string& name, const std::string& key) + : mName(name), mKey(key) {} + + virtual void execute(); + private: + std::string mName; + std::string mKey; + }; + + // pass + + class ActionCreatePass : public Action + { + public: + ActionCreatePass (const std::string& name) + : mName(name) {} + + virtual void execute(); + private: + std::string mName; + }; + + class ActionDeletePass : public Action + { + public: + ActionDeletePass (const std::string& name, int passIndex) + : mName(name), mPassIndex(passIndex) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + }; + + class ActionSetPassProperty : public Action + { + public: + ActionSetPassProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) + : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + std::string mKey; + std::string mValue; + }; + + class ActionDeletePassProperty : public Action + { + public: + ActionDeletePassProperty (const std::string& name, int passIndex, const std::string& key) + : mName(name), mPassIndex(passIndex), mKey(key) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + std::string mKey; + }; + + // shader + + class ActionSetShaderProperty : public Action + { + public: + ActionSetShaderProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value) + : mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + std::string mKey; + std::string mValue; + }; + + class ActionDeleteShaderProperty : public Action + { + public: + ActionDeleteShaderProperty (const std::string& name, int passIndex, const std::string& key) + : mName(name), mPassIndex(passIndex), mKey(key) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + std::string mKey; + }; + + // texture unit + + class ActionChangeTextureUnitName : public Action + { + public: + ActionChangeTextureUnitName (const std::string& name, int passIndex, int textureIndex, const std::string& texUnitName) + : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mTexUnitName(texUnitName) {} + + virtual void execute(); + + private: + std::string mName; + int mPassIndex; + int mTextureIndex; + std::string mTexUnitName; + }; + + class ActionCreateTextureUnit : public Action + { + public: + ActionCreateTextureUnit (const std::string& name, int passIndex, const std::string& texUnitName) + : mName(name), mPassIndex(passIndex), mTexUnitName(texUnitName) {} + + virtual void execute(); + + private: + std::string mName; + int mPassIndex; + std::string mTexUnitName; + }; + + class ActionDeleteTextureUnit : public Action + { + public: + ActionDeleteTextureUnit (const std::string& name, int passIndex, int textureIndex) + : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex) {} + + virtual void execute(); + + private: + std::string mName; + int mPassIndex; + int mTextureIndex; + }; + + class ActionMoveTextureUnit : public Action + { + public: + ActionMoveTextureUnit (const std::string& name, int passIndex, int textureIndex, bool moveUp) + : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mMoveUp(moveUp) {} + + virtual void execute(); + + private: + std::string mName; + int mPassIndex; + int mTextureIndex; + bool mMoveUp; + }; + + class ActionSetTextureProperty : public Action + { + public: + ActionSetTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key, const std::string& value) + : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key), mValue(value) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + int mTextureIndex; + std::string mKey; + std::string mValue; + }; + + class ActionDeleteTextureProperty : public Action + { + public: + ActionDeleteTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key) + : mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key) {} + + virtual void execute(); + private: + std::string mName; + int mPassIndex; + int mTextureIndex; + std::string mKey; + }; + +} + +#endif diff --git a/extern/shiny/Editor/AddPropertyDialog.cpp b/extern/shiny/Editor/AddPropertyDialog.cpp new file mode 100644 index 0000000000..71b47feb19 --- /dev/null +++ b/extern/shiny/Editor/AddPropertyDialog.cpp @@ -0,0 +1,31 @@ +#include "AddPropertyDialog.hpp" +#include "ui_addpropertydialog.h" + +AddPropertyDialog::AddPropertyDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::AddPropertyDialog) + , mType(0) +{ + ui->setupUi(this); + + connect(ui->buttonBox, SIGNAL(accepted()), + this, SLOT(accepted())); + connect(ui->buttonBox, SIGNAL(rejected()), + this, SLOT(rejected())); +} + +void AddPropertyDialog::accepted() +{ + mName = ui->lineEdit->text(); + mType = ui->comboBox->currentIndex(); +} + +void AddPropertyDialog::rejected() +{ + mName = ""; +} + +AddPropertyDialog::~AddPropertyDialog() +{ + delete ui; +} diff --git a/extern/shiny/Editor/AddPropertyDialog.h b/extern/shiny/Editor/AddPropertyDialog.h new file mode 100644 index 0000000000..c1d2c960b5 --- /dev/null +++ b/extern/shiny/Editor/AddPropertyDialog.h @@ -0,0 +1,22 @@ +#ifndef ADDPROPERTYDIALOG_H +#define ADDPROPERTYDIALOG_H + +#include + +namespace Ui { +class AddPropertyDialog; +} + +class AddPropertyDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddPropertyDialog(QWidget *parent = 0); + ~AddPropertyDialog(); + +private: + Ui::AddPropertyDialog *ui; +}; + +#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/AddPropertyDialog.hpp b/extern/shiny/Editor/AddPropertyDialog.hpp new file mode 100644 index 0000000000..b4e19b0870 --- /dev/null +++ b/extern/shiny/Editor/AddPropertyDialog.hpp @@ -0,0 +1,29 @@ +#ifndef ADDPROPERTYDIALOG_H +#define ADDPROPERTYDIALOG_H + +#include + +namespace Ui { +class AddPropertyDialog; +} + +class AddPropertyDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddPropertyDialog(QWidget *parent = 0); + ~AddPropertyDialog(); + + int mType; + QString mName; + +public slots: + void accepted(); + void rejected(); + +private: + Ui::AddPropertyDialog *ui; +}; + +#endif // ADDPROPERTYDIALOG_H diff --git a/extern/shiny/Editor/CMakeLists.txt b/extern/shiny/Editor/CMakeLists.txt new file mode 100644 index 0000000000..eead159f08 --- /dev/null +++ b/extern/shiny/Editor/CMakeLists.txt @@ -0,0 +1,61 @@ +set(SHINY_EDITOR_LIBRARY "shiny.Editor") + +find_package(Qt4) + +if (QT_FOUND) + + add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=1) + set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=1 PARENT_SCOPE) + + set(QT_USE_QTGUI 1) + + # Headers that must be preprocessed + set(SHINY_EDITOR_HEADER_MOC + MainWindow.hpp + NewMaterialDialog.hpp + AddPropertyDialog.hpp + PropertySortModel.hpp + ) + + set(SHINY_EDITOR_UI + mainwindow.ui + newmaterialdialog.ui + addpropertydialog.ui + ) + + QT4_WRAP_CPP(MOC_SRCS ${SHINY_EDITOR_HEADER_MOC}) + QT4_WRAP_UI(UI_HDRS ${SHINY_EDITOR_UI}) + + set(SOURCE_FILES + NewMaterialDialog.cpp + AddPropertyDialog.cpp + ColoredTabWidget.hpp + MainWindow.cpp + Editor.cpp + Actions.cpp + Query.cpp + PropertySortModel.cpp + ${SHINY_EDITOR_UI} # Just to have them in the IDE's file explorer + ) + + include(${QT_USE_FILE}) + + set (CMAKE_INCLUDE_CURRENT_DIR "true") + + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + add_library(${SHINY_EDITOR_LIBRARY} STATIC ${SOURCE_FILES} ${MOC_SRCS} ${UI_HDRS}) + + set(SHINY_LIBRARIES ${SHINY_LIBRARIES} + ${SHINY_EDITOR_LIBRARY} + ${QT_LIBRARIES} + ) + set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) + +else (QT_FOUND) + + add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=0) + set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=0 PARENT_SCOPE) + message(STATUS "QT4 was not found. You will not be able to use the material editor.") + +endif(QT_FOUND) diff --git a/extern/shiny/Editor/ColoredTabWidget.hpp b/extern/shiny/Editor/ColoredTabWidget.hpp new file mode 100644 index 0000000000..0bf30f6dda --- /dev/null +++ b/extern/shiny/Editor/ColoredTabWidget.hpp @@ -0,0 +1,24 @@ +#ifndef SHINY_EDITOR_COLOREDTABWIDGET_H +#define SHINY_EDITOR_COLOREDTABWIDGET_H + +#include + +namespace sh +{ + +/// Makes tabBar() public to allow changing tab title colors. +class ColoredTabWidget : public QTabWidget +{ +public: + ColoredTabWidget(QWidget* parent = 0) + : QTabWidget(parent) {} + + QTabBar* tabBar() + { + return QTabWidget::tabBar(); + } +}; + +} + +#endif diff --git a/extern/shiny/Editor/Editor.cpp b/extern/shiny/Editor/Editor.cpp new file mode 100644 index 0000000000..8c58d0e66d --- /dev/null +++ b/extern/shiny/Editor/Editor.cpp @@ -0,0 +1,117 @@ +#include "Editor.hpp" + + +#include +#include + +#include + +#include "../Main/Factory.hpp" + +#include "MainWindow.hpp" + +namespace sh +{ + + Editor::Editor() + : mMainWindow(NULL) + , mApplication(NULL) + , mInitialized(false) + , mThread(NULL) + { + } + + Editor::~Editor() + { + if (mMainWindow) + mMainWindow->mRequestExit = true; + + if (mThread) + mThread->join(); + delete mThread; + } + + void Editor::show() + { + if (!mInitialized) + { + mInitialized = true; + + mThread = new boost::thread(boost::bind(&Editor::runThread, this)); + } + else + { + if (mMainWindow) + mMainWindow->mRequestShowWindow = true; + } + } + + void Editor::runThread() + { + int argc = 0; + char** argv = NULL; + mApplication = new QApplication(argc, argv); + mApplication->setQuitOnLastWindowClosed(false); + mMainWindow = new MainWindow(); + mMainWindow->mSync = &mSync; + mMainWindow->show(); + + mApplication->exec(); + + delete mApplication; + } + + void Editor::update() + { + sh::Factory::getInstance().doMonitorShaderFiles(); + + if (!mMainWindow) + return; + + + { + boost::mutex::scoped_lock lock(mSync.mActionMutex); + + // execute pending actions + while (mMainWindow->mActionQueue.size()) + { + Action* action = mMainWindow->mActionQueue.front(); + action->execute(); + delete action; + mMainWindow->mActionQueue.pop(); + } + } + { + boost::mutex::scoped_lock lock(mSync.mQueryMutex); + + // execute pending queries + for (std::vector::iterator it = mMainWindow->mQueries.begin(); it != mMainWindow->mQueries.end(); ++it) + { + Query* query = *it; + if (!query->mDone) + query->execute(); + } + } + + boost::mutex::scoped_lock lock2(mSync.mUpdateMutex); + + // update the list of materials + mMainWindow->mState.mMaterialList.clear(); + sh::Factory::getInstance().listMaterials(mMainWindow->mState.mMaterialList); + + // update global settings + mMainWindow->mState.mGlobalSettingsMap.clear(); + sh::Factory::getInstance().listGlobalSettings(mMainWindow->mState.mGlobalSettingsMap); + + // update configuration list + mMainWindow->mState.mConfigurationList.clear(); + sh::Factory::getInstance().listConfigurationNames(mMainWindow->mState.mConfigurationList); + + // update shader list + mMainWindow->mState.mShaderSets.clear(); + sh::Factory::getInstance().listShaderSets(mMainWindow->mState.mShaderSets); + + mMainWindow->mState.mErrors += sh::Factory::getInstance().getErrorLog(); + } + +} diff --git a/extern/shiny/Editor/Editor.hpp b/extern/shiny/Editor/Editor.hpp new file mode 100644 index 0000000000..2b1e8040d0 --- /dev/null +++ b/extern/shiny/Editor/Editor.hpp @@ -0,0 +1,73 @@ +#ifndef SH_EDITOR_H +#define SH_EDITOR_H + +#if SHINY_BUILD_MATERIAL_EDITOR +class QApplication; + +#include +#include + +namespace boost +{ + class thread; +} + +namespace sh +{ + class MainWindow; + + struct SynchronizationState + { + boost::mutex mUpdateMutex; + boost::mutex mActionMutex; + boost::mutex mQueryMutex; + }; + + class Editor + { + public: + + Editor(); + ~Editor(); + + void show(); + void update(); + + + private: + bool mInitialized; + + MainWindow* mMainWindow; + QApplication* mApplication; + + SynchronizationState mSync; + + boost::thread* mThread; + + void runThread(); + + void processShowWindow(); + }; + +} + +#else + +// Dummy implementation, so that the user's code does not have to be polluted with #ifdefs +namespace sh +{ + + class Editor + { + public: + Editor() {} + ~Editor() {} + void show() {} + void update() {} + + }; +} + +#endif + +#endif diff --git a/extern/shiny/Editor/MainWindow.cpp b/extern/shiny/Editor/MainWindow.cpp new file mode 100644 index 0000000000..1d46719cea --- /dev/null +++ b/extern/shiny/Editor/MainWindow.cpp @@ -0,0 +1,950 @@ +#include "MainWindow.hpp" +#include "ui_mainwindow.h" + +#include +#include + +#include +#include + +#include "Editor.hpp" +#include "ColoredTabWidget.hpp" +#include "AddPropertyDialog.hpp" + +sh::MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) + , mRequestShowWindow(false) + , mRequestExit(false) + , mIgnoreGlobalSettingChange(false) + , mIgnoreConfigurationChange(false) + , mIgnoreMaterialChange(false) + , mIgnoreMaterialPropertyChange(false) +{ + ui->setupUi(this); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(onIdle())); + timer->start(50); + + QList sizes; + sizes << 250; + sizes << 550; + ui->splitter->setSizes(sizes); + + mMaterialModel = new QStringListModel(this); + + mMaterialProxyModel = new QSortFilterProxyModel(this); + mMaterialProxyModel->setSourceModel(mMaterialModel); + mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mMaterialProxyModel->setDynamicSortFilter(true); + mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + + ui->materialList->setModel(mMaterialProxyModel); + ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection); + ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->materialList->setAlternatingRowColors(true); + + connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex))); + + mMaterialPropertyModel = new QStandardItemModel(0, 2, this); + mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); + mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); + connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)), + this, SLOT(onMaterialPropertyChanged(QStandardItem*))); + + mMaterialSortModel = new PropertySortModel(this); + mMaterialSortModel->setSourceModel(mMaterialPropertyModel); + mMaterialSortModel->setDynamicSortFilter(true); + mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive); + + ui->materialView->setModel(mMaterialSortModel); + ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu); + ui->materialView->setAlternatingRowColors(true); + ui->materialView->setSortingEnabled(true); + connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(onContextMenuRequested(QPoint))); + + mGlobalSettingsModel = new QStandardItemModel(0, 2, this); + mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); + mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); + connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)), + this, SLOT(onGlobalSettingChanged(QStandardItem*))); + + ui->globalSettingsView->setModel(mGlobalSettingsModel); + ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); + ui->globalSettingsView->verticalHeader()->hide(); + ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection); + + ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection); + ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers); + connect(ui->configurationList, SIGNAL(currentTextChanged(QString)), + this, SLOT(onConfigurationSelectionChanged(QString))); + + mConfigurationModel = new QStandardItemModel(0, 2, this); + mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); + mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); + connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)), + this, SLOT(onConfigurationChanged(QStandardItem*))); + + ui->configurationView->setModel(mConfigurationModel); + ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents); + ui->configurationView->verticalHeader()->hide(); + ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection); +} + +sh::MainWindow::~MainWindow() +{ + delete ui; +} + +void sh::MainWindow::closeEvent(QCloseEvent *event) +{ + this->hide(); + event->ignore(); +} + +void sh::MainWindow::onIdle() +{ + if (mRequestShowWindow) + { + mRequestShowWindow = false; + show(); + } + + if (mRequestExit) + { + QApplication::exit(); + return; + } + + boost::mutex::scoped_lock lock(mSync->mUpdateMutex); + + + mIgnoreMaterialChange = true; + QString selected; + + QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); + if (selectedIndex.isValid()) + selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString(); + + QStringList list; + + for (std::vector::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it) + { + list.push_back(QString::fromStdString(*it)); + } + + if (mMaterialModel->stringList() != list) + { + mMaterialModel->setStringList(list); + + // quick hack to keep our selection when the model has changed + if (!selected.isEmpty()) + for (int i=0; irowCount(); ++i) + { + const QModelIndex& index = mMaterialModel->index(i,0); + if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected) + { + ui->materialList->setCurrentIndex(index); + break; + } + } + } + mIgnoreMaterialChange = false; + + mIgnoreGlobalSettingChange = true; + for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); + it != mState.mGlobalSettingsMap.end(); ++it) + { + QList list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first)); + if (!list.empty()) // item was already there + { + // if it changed, set the value column + if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString() + != QString::fromStdString(it->second)) + { + mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second))); + } + } + else // item wasn't there; insert new row + { + QList toAdd; + QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); + name->setFlags(name->flags() &= ~Qt::ItemIsEditable); + QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); + toAdd.push_back(name); + toAdd.push_back(value); + mGlobalSettingsModel->appendRow(toAdd); + } + } + mIgnoreGlobalSettingChange = false; + + + mIgnoreConfigurationChange = true; + QList selected_ = ui->configurationList->selectedItems(); + QString selectedStr; + if (selected_.size()) + selectedStr = selected_.front()->text(); + + ui->configurationList->clear(); + + for (std::vector::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it) + ui->configurationList->addItem(QString::fromStdString(*it)); + + if (!selectedStr.isEmpty()) + for (int i=0; iconfigurationList->count(); ++i) + { + if (ui->configurationList->item(i)->text() == selectedStr) + { + ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect); + } + } + + mIgnoreConfigurationChange = false; + + if (!mState.mErrors.empty()) + { + ui->errorLog->append(QString::fromStdString(mState.mErrors)); + mState.mErrors = ""; + QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link); + ui->tabWidget->tabBar()->setTabTextColor(3, color); + } + + + // process query results + boost::mutex::scoped_lock lock2(mSync->mQueryMutex); + for (std::vector::iterator it = mQueries.begin(); it != mQueries.end();) + { + if ((*it)->mDone) + { + if (typeid(**it) == typeid(ConfigurationQuery)) + buildConfigurationModel(static_cast(*it)); + else if (typeid(**it) == typeid(MaterialQuery)) + buildMaterialModel(static_cast(*it)); + else if (typeid(**it) == typeid(MaterialPropertyQuery)) + { + MaterialPropertyQuery* q = static_cast(*it); + mIgnoreMaterialPropertyChange = true; + if (getSelectedMaterial().toStdString() == q->mName) + { + for (int i=0; irowCount(); ++i) + { + if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName)) + { + mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue)); + if (mMaterialPropertyModel->item(i,1)->isCheckable()) + mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true") + ? Qt::Checked : Qt::Unchecked); + } + } + } + mIgnoreMaterialPropertyChange = false; + } + + delete *it; + it = mQueries.erase(it); + } + else + ++it; + } +} + +void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous) +{ + if (mIgnoreMaterialChange) + return; + + QString name = getSelectedMaterial(); + if (!name.isEmpty()) + requestQuery(new sh::MaterialQuery(name.toStdString())); +} + +QString sh::MainWindow::getSelectedMaterial() +{ + QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); + if (!selectedIndex.isValid()) + return QString(""); + + return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); +} + +void sh::MainWindow::onConfigurationSelectionChanged (const QString& current) +{ + if (mIgnoreConfigurationChange) + return; + requestQuery(new sh::ConfigurationQuery(current.toStdString())); +} + +void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item) +{ + if (mIgnoreGlobalSettingChange) + return; // we are only interested in changes by the user, not by the backend. + + std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString(); + std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString(); + + queueAction(new sh::ActionChangeGlobalSetting(name, value)); +} + +void sh::MainWindow::onConfigurationChanged (QStandardItem* item) +{ + QList items = ui->configurationList->selectedItems(); + if (items.size()) + { + std::string name = items.front()->text().toStdString(); + std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString(); + std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString(); + + queueAction(new sh::ActionChangeConfiguration(name, key, value)); + + requestQuery(new sh::ConfigurationQuery(name)); + } +} + +void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1) +{ + mMaterialProxyModel->setFilterFixedString(arg1); +} + +void sh::MainWindow::on_actionSave_triggered() +{ + queueAction (new sh::ActionSaveAll()); +} + +void sh::MainWindow::on_actionNewMaterial_triggered() +{ + +} + +void sh::MainWindow::on_actionDeleteMaterial_triggered() +{ + QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); + QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); + + queueAction (new sh::ActionDeleteMaterial(name.toStdString())); +} + +void sh::MainWindow::queueAction(Action* action) +{ + boost::mutex::scoped_lock lock(mSync->mActionMutex); + mActionQueue.push(action); +} + +void sh::MainWindow::requestQuery(Query *query) +{ + boost::mutex::scoped_lock lock(mSync->mActionMutex); + mQueries.push_back(query); +} + +void sh::MainWindow::on_actionQuit_triggered() +{ + hide(); +} + +void sh::MainWindow::on_actionNewConfiguration_triggered() +{ + QInputDialog dialog(this); + + QString text = QInputDialog::getText(this, tr("New Configuration"), + tr("Configuration name:")); + + if (!text.isEmpty()) + { + queueAction(new ActionCreateConfiguration(text.toStdString())); + } +} + +void sh::MainWindow::on_actionDeleteConfiguration_triggered() +{ + QList items = ui->configurationList->selectedItems(); + if (items.size()) + queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString())); +} + +void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered() +{ + QList items = ui->configurationList->selectedItems(); + if (items.empty()) + return; + std::string configurationName = items.front()->text().toStdString(); + + QModelIndex current = ui->configurationView->currentIndex(); + if (!current.isValid()) + return; + + std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString(); + + queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName)); + requestQuery(new sh::ConfigurationQuery(configurationName)); +} + +void sh::MainWindow::on_actionCloneMaterial_triggered() +{ + QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex(); + QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString(); + if (name.isEmpty()) + return; + + QInputDialog dialog(this); + + QString text = QInputDialog::getText(this, tr("Clone material"), + tr("Name:")); + + if (!text.isEmpty()) + { + queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString())); + } +} + +void sh::MainWindow::onContextMenuRequested(const QPoint &point) +{ + QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point); + + QMenu menu; + + QList actions; + actions.push_back(ui->actionNewProperty); + actions.push_back(ui->actionDeleteProperty); + actions.push_back(ui->actionCreatePass); + actions.push_back(ui->actionCreateTextureUnit); + menu.addActions(actions); + + menu.exec(globalPos); +} + +void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit) +{ + if (passIndex) + { + *passIndex = 0; + if (isInPass) + *isInPass = false; + QModelIndex passModelIndex = index; + // go up until we find the pass item. + while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid()) + passModelIndex = passModelIndex.parent(); + + if (passModelIndex.isValid()) + { + if (passModelIndex.column() != 0) + passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0); + for (int i=0; irowCount(); ++i) + { + if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) + { + if (mMaterialPropertyModel->index(i, 0) == passModelIndex) + { + if (isInPass) + *isInPass = true; + break; + } + ++(*passIndex); + } + } + } + } + if (textureIndex) + { + *textureIndex = 0; + if (isInTextureUnit) + *isInTextureUnit = false; + QModelIndex texModelIndex = index; + // go up until we find the texture_unit item. + while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid()) + texModelIndex = texModelIndex.parent(); + if (texModelIndex.isValid()) + { + if (texModelIndex.column() != 0) + texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0); + for (int i=0; irowCount(texModelIndex.parent()); ++i) + { + if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit")) + { + if (texModelIndex.parent().child(i, 0) == texModelIndex) + { + if (isInTextureUnit) + *isInTextureUnit = true; + break; + } + ++(*textureIndex); + } + } + } + } +} + +std::string sh::MainWindow::getPropertyKey(QModelIndex index) +{ + if (!index.parent().isValid()) + return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString(); + else + return index.parent().child(index.row(), 0).data().toString().toStdString(); +} + +std::string sh::MainWindow::getPropertyValue(QModelIndex index) +{ + if (!index.parent().isValid()) + return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString(); + else + return index.parent().child(index.row(), 1).data().toString().toStdString(); +} + +void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item) +{ + if (mIgnoreMaterialPropertyChange) + return; + + QString material = getSelectedMaterial(); + if (material.isEmpty()) + return; + + // handle checkboxes being checked/unchecked + std::string value = getPropertyValue(item->index()); + if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean) + { + if (item->checkState() == Qt::Checked && value != "true") + value = "true"; + else if (item->checkState() == Qt::Unchecked && value == "true") + value = "false"; + item->setText(QString::fromStdString(value)); + } + + // handle inherited properties being changed, i.e. overridden by the current (derived) material + if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged) + { + QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText); + mIgnoreMaterialPropertyChange = true; + mMaterialPropertyModel->item(item->index().row(), 0) + ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); + mMaterialPropertyModel->item(item->index().row(), 0) + ->setData(normalColor, Qt::ForegroundRole); + mMaterialPropertyModel->item(item->index().row(), 1) + ->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1); + mMaterialPropertyModel->item(item->index().row(), 1) + ->setData(normalColor, Qt::ForegroundRole); + mIgnoreMaterialPropertyChange = false; + + ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index())); + } + + if (!item->index().parent().isValid()) + { + // top level material property + queueAction(new ActionSetMaterialProperty( + material.toStdString(), getPropertyKey(item->index()), value)); + } + else if (getPropertyKey(item->index()) == "texture_unit") + { + // texture unit name changed + int passIndex, textureIndex; + getContext(item->index(), &passIndex, &textureIndex); + std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl; + + queueAction(new ActionChangeTextureUnitName( + material.toStdString(), passIndex, textureIndex, value)); + + } + else if (item->index().parent().data().toString() == "pass") + { + // pass property + int passIndex; + getContext(item->index(), &passIndex, NULL); + /// \todo if shaders are changed, check that the material provides all properties needed by the shader + queueAction(new ActionSetPassProperty( + material.toStdString(), passIndex, getPropertyKey(item->index()), value)); + } + else if (item->index().parent().data().toString() == "shader_properties") + { + // shader property + int passIndex; + getContext(item->index(), &passIndex, NULL); + queueAction(new ActionSetShaderProperty( + material.toStdString(), passIndex, getPropertyKey(item->index()), value)); + } + else if (item->index().parent().data().toString() == "texture_unit") + { + // texture property + int passIndex, textureIndex; + getContext(item->index(), &passIndex, &textureIndex); + queueAction(new ActionSetTextureProperty( + material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value)); + } +} + +void sh::MainWindow::buildMaterialModel(MaterialQuery *data) +{ + mMaterialPropertyModel->clear(); + + mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name"))); + mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value"))); + + for (std::map::const_iterator it = data->mProperties.begin(); + it != data->mProperties.end(); ++it) + { + addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second); + } + + for (std::vector::iterator it = data->mPasses.begin(); + it != data->mPasses.end(); ++it) + { + QStandardItem* passItem = new QStandardItem (QString("pass")); + passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable); + passItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); + + if (it->mShaderProperties.size()) + { + QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties")); + shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable); + shaderPropertiesItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); + + for (std::map::iterator pit = it->mShaderProperties.begin(); + pit != it->mShaderProperties.end(); ++pit) + { + addProperty(shaderPropertiesItem, pit->first, pit->second); + } + passItem->appendRow(shaderPropertiesItem); + } + + for (std::map::iterator pit = it->mProperties.begin(); + pit != it->mProperties.end(); ++pit) + { + addProperty(passItem, pit->first, pit->second); + } + + for (std::vector::iterator tIt = it->mTextureUnits.begin(); + tIt != it->mTextureUnits.end(); ++tIt) + { + QStandardItem* unitItem = new QStandardItem (QString("texture_unit")); + unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable); + unitItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); + QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName)); + nameItem->setData(QVariant(static_cast(MaterialProperty::Object)), Qt::UserRole); + + QList texUnit; + texUnit << unitItem << nameItem; + + for (std::map::iterator pit = tIt->mProperties.begin(); + pit != tIt->mProperties.end(); ++pit) + { + addProperty(unitItem, pit->first, pit->second); + } + + passItem->appendRow(texUnit); + } + + QList toAdd; + toAdd << passItem; + toAdd << new QStandardItem(QString("")); + mMaterialPropertyModel->appendRow(toAdd); + } + + ui->materialView->expandAll(); + ui->materialView->resizeColumnToContents(0); + ui->materialView->resizeColumnToContents(1); +} + +void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo) +{ + QList toAdd; + QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key)); + keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); + keyItem->setData(QVariant(value.mType), Qt::UserRole); + keyItem->setData(QVariant(value.mSource), Qt::UserRole+1); + toAdd.push_back(keyItem); + + QStandardItem* valueItem = NULL; + if (value.mSource != MaterialProperty::None) + { + valueItem = new QStandardItem(QString::fromStdString(value.mValue)); + valueItem->setData(QVariant(value.mType), Qt::UserRole); + valueItem->setData(QVariant(value.mSource), Qt::UserRole+1); + toAdd.push_back(valueItem); + } + + + if (value.mSource == MaterialProperty::Inherited_Unchanged) + { + QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); + keyItem->setData(color, Qt::ForegroundRole); + if (valueItem) + valueItem->setData(color, Qt::ForegroundRole); + } + if (value.mType == MaterialProperty::Boolean && valueItem) + { + valueItem->setCheckable(true); + valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked); + } + + parent->appendRow(toAdd); + + if (scrollTo) + ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index())); +} + +void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data) +{ + while (mConfigurationModel->rowCount()) + mConfigurationModel->removeRow(0); + for (std::map::iterator it = data->mProperties.begin(); + it != data->mProperties.end(); ++it) + { + QList toAdd; + QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); + name->setFlags(name->flags() &= ~Qt::ItemIsEditable); + QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); + toAdd.push_back(name); + toAdd.push_back(value); + mConfigurationModel->appendRow(toAdd); + } + + // add items that are in global settings, but not in this configuration (with a "inactive" color) + for (std::map::const_iterator it = mState.mGlobalSettingsMap.begin(); + it != mState.mGlobalSettingsMap.end(); ++it) + { + if (data->mProperties.find(it->first) == data->mProperties.end()) + { + QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText); + QList toAdd; + QStandardItem* name = new QStandardItem(QString::fromStdString(it->first)); + name->setFlags(name->flags() &= ~Qt::ItemIsEditable); + name->setData(color, Qt::ForegroundRole); + QStandardItem* value = new QStandardItem(QString::fromStdString(it->second)); + value->setData(color, Qt::ForegroundRole); + toAdd.push_back(name); + toAdd.push_back(value); + mConfigurationModel->appendRow(toAdd); + } + } +} + +void sh::MainWindow::on_actionCreatePass_triggered() +{ + QString material = getSelectedMaterial(); + if (!material.isEmpty()) + { + addProperty(mMaterialPropertyModel->invisibleRootItem(), + "pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true); + + queueAction (new ActionCreatePass(material.toStdString())); + } +} + +void sh::MainWindow::on_actionDeleteProperty_triggered() +{ + QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); + QString material = getSelectedMaterial(); + if (material.isEmpty()) + return; + + mIgnoreMaterialPropertyChange = true; + + if (getPropertyKey(selectedIndex) == "pass") + { + // delete whole pass + int passIndex; + getContext(selectedIndex, &passIndex, NULL); + if (passIndex == 0) + { + QMessageBox msgBox; + msgBox.setText("The first pass can not be deleted."); + msgBox.exec(); + } + else + { + queueAction(new ActionDeletePass(material.toStdString(), passIndex)); + mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); + } + } + else if (getPropertyKey(selectedIndex) == "texture_unit") + { + // delete whole texture unit + int passIndex, textureIndex; + getContext(selectedIndex, &passIndex, &textureIndex); + queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex)); + mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); + } + else if (!selectedIndex.parent().isValid()) + { + // top level material property + MaterialProperty::Source source = static_cast( + mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt()); + if (source == MaterialProperty::Inherited_Unchanged) + { + QMessageBox msgBox; + msgBox.setText("Inherited properties can not be deleted."); + msgBox.exec(); + } + else + { + queueAction(new ActionDeleteMaterialProperty( + material.toStdString(), getPropertyKey(selectedIndex))); + std::cout << "source is " << source << std::endl; + if (source == MaterialProperty::Inherited_Changed) + { + QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText); + mMaterialPropertyModel->item(selectedIndex.row(), 0) + ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); + mMaterialPropertyModel->item(selectedIndex.row(), 0) + ->setData(inactiveColor, Qt::ForegroundRole); + mMaterialPropertyModel->item(selectedIndex.row(), 1) + ->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1); + mMaterialPropertyModel->item(selectedIndex.row(), 1) + ->setData(inactiveColor, Qt::ForegroundRole); + + // make sure to update the property's value + requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex))); + } + else + mMaterialPropertyModel->removeRow(selectedIndex.row()); + } + } + else if (selectedIndex.parent().data().toString() == "pass") + { + // pass property + int passIndex; + getContext(selectedIndex, &passIndex, NULL); + queueAction(new ActionDeletePassProperty( + material.toStdString(), passIndex, getPropertyKey(selectedIndex))); + mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); + } + else if (selectedIndex.parent().data().toString() == "shader_properties") + { + // shader property + int passIndex; + getContext(selectedIndex, &passIndex, NULL); + queueAction(new ActionDeleteShaderProperty( + material.toStdString(), passIndex, getPropertyKey(selectedIndex))); + mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); + } + else if (selectedIndex.parent().data().toString() == "texture_unit") + { + // texture property + int passIndex, textureIndex; + getContext(selectedIndex, &passIndex, &textureIndex); + queueAction(new ActionDeleteTextureProperty( + material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex))); + mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent()); + } + mIgnoreMaterialPropertyChange = false; +} + +void sh::MainWindow::on_actionNewProperty_triggered() +{ + QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); + QString material = getSelectedMaterial(); + if (material.isEmpty()) + return; + + AddPropertyDialog* dialog = new AddPropertyDialog(this); + dialog->exec(); + QString propertyName = dialog->mName; + QString defaultValue = ""; + + /// \todo check if this property name exists already + + if (!propertyName.isEmpty()) + { + int passIndex, textureIndex; + bool isInPass, isInTextureUnit; + getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit); + + QList items; + QStandardItem* keyItem = new QStandardItem(propertyName); + keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable); + items << keyItem; + items << new QStandardItem(defaultValue); + + // figure out which item the new property should be a child of + QModelIndex parentIndex = selectedIndex; + if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object) + parentIndex = selectedIndex.parent(); + QStandardItem* parentItem; + if (!parentIndex.isValid()) + parentItem = mMaterialPropertyModel->invisibleRootItem(); + else + parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex); + + if (isInTextureUnit) + { + queueAction(new ActionSetTextureProperty( + material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString())); + } + else if (isInPass) + { + if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties" + || selectedIndex.parent().data().toString() == "shader_properties") + { + queueAction(new ActionSetShaderProperty( + material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); + } + else + { + queueAction(new ActionSetPassProperty( + material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString())); + } + } + else + { + queueAction(new ActionSetMaterialProperty( + material.toStdString(), propertyName.toStdString(), defaultValue.toStdString())); + } + + addProperty(parentItem, propertyName.toStdString(), + MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true); + + /// \todo scroll to newly added property + } +} + +void sh::MainWindow::on_actionCreateTextureUnit_triggered() +{ + QString material = getSelectedMaterial(); + if (material.isEmpty()) + return; + + QInputDialog dialog(this); + + QString text = QInputDialog::getText(this, tr("New texture unit"), + tr("Texture unit name (for referencing in shaders):")); + if (!text.isEmpty()) + { + QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex()); + int passIndex; + getContext(selectedIndex, &passIndex, NULL); + queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString())); + + // add to model + int index = 0; + for (int i=0; irowCount(); ++i) + { + if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass")) + { + if (index == passIndex) + { + addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)), + "texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true); + break; + } + + ++index; + } + } + } +} + +void sh::MainWindow::on_clearButton_clicked() +{ + ui->errorLog->clear(); +} + +void sh::MainWindow::on_tabWidget_currentChanged(int index) +{ + QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText); + + if (index == 3) + ui->tabWidget->tabBar()->setTabTextColor(3, color); +} diff --git a/extern/shiny/Editor/MainWindow.hpp b/extern/shiny/Editor/MainWindow.hpp new file mode 100644 index 0000000000..3f0dc295c0 --- /dev/null +++ b/extern/shiny/Editor/MainWindow.hpp @@ -0,0 +1,139 @@ +#ifndef SHINY_EDITOR_MAINWINDOW_HPP +#define SHINY_EDITOR_MAINWINDOW_HPP + +#include + +#include +#include +#include + +#include + +#include "Actions.hpp" +#include "Query.hpp" + +#include "PropertySortModel.hpp" + +namespace Ui { +class MainWindow; +} + +namespace sh +{ + +struct SynchronizationState; + + +/** + * @brief A snapshot of the material system's state. Lock the mUpdateMutex before accessing. + */ +struct MaterialSystemState +{ + std::vector mMaterialList; + + std::map mGlobalSettingsMap; + + std::vector mConfigurationList; + + std::vector mMaterialFiles; + std::vector mConfigurationFiles; + + std::vector mShaderSets; + + std::string mErrors; +}; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + // really should be an std::atomic + volatile bool mRequestShowWindow; + // dito + volatile bool mRequestExit; + + SynchronizationState* mSync; + + /// \todo Is there a better way to ignore manual model changes? + bool mIgnoreGlobalSettingChange; + bool mIgnoreConfigurationChange; + bool mIgnoreMaterialChange; + bool mIgnoreMaterialPropertyChange; + + std::queue mActionQueue; + std::vector mQueries; + + MaterialSystemState mState; + +private: + Ui::MainWindow *ui; + + // material tab + QStringListModel* mMaterialModel; + QSortFilterProxyModel* mMaterialProxyModel; + + QStandardItemModel* mMaterialPropertyModel; + PropertySortModel* mMaterialSortModel; + + // global settings tab + QStandardItemModel* mGlobalSettingsModel; + + // configuration tab + QStandardItemModel* mConfigurationModel; + + void queueAction(Action* action); + void requestQuery(Query* query); + + void buildMaterialModel (MaterialQuery* data); + void buildConfigurationModel (ConfigurationQuery* data); + + QString getSelectedMaterial(); + + /// get the context of an index in the material property model + void getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass=NULL, bool* isInTextureUnit=NULL); + + std::string getPropertyKey(QModelIndex index); + std::string getPropertyValue(QModelIndex index); + + void addProperty (QStandardItem* parent, const std::string& key, MaterialProperty value, bool scrollTo=false); + +protected: + void closeEvent(QCloseEvent *event); + +public slots: + void onIdle(); + + void onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous); + void onConfigurationSelectionChanged (const QString& current); + + void onGlobalSettingChanged (QStandardItem* item); + void onConfigurationChanged (QStandardItem* item); + void onMaterialPropertyChanged (QStandardItem* item); + + void onContextMenuRequested(const QPoint& point); + +private slots: + void on_lineEdit_textEdited(const QString &arg1); + void on_actionSave_triggered(); + void on_actionNewMaterial_triggered(); + void on_actionDeleteMaterial_triggered(); + void on_actionQuit_triggered(); + void on_actionNewConfiguration_triggered(); + void on_actionDeleteConfiguration_triggered(); + void on_actionDeleteConfigurationProperty_triggered(); + void on_actionCloneMaterial_triggered(); + void on_actionCreatePass_triggered(); + void on_actionDeleteProperty_triggered(); + void on_actionNewProperty_triggered(); + void on_actionCreateTextureUnit_triggered(); + void on_clearButton_clicked(); + void on_tabWidget_currentChanged(int index); +}; + +} + +#endif // MAINWINDOW_HPP diff --git a/extern/shiny/Editor/NewMaterialDialog.cpp b/extern/shiny/Editor/NewMaterialDialog.cpp new file mode 100644 index 0000000000..f1a716a9f0 --- /dev/null +++ b/extern/shiny/Editor/NewMaterialDialog.cpp @@ -0,0 +1,14 @@ +#include "NewMaterialDialog.hpp" +#include "ui_newmaterialdialog.h" + +NewMaterialDialog::NewMaterialDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::NewMaterialDialog) +{ + ui->setupUi(this); +} + +NewMaterialDialog::~NewMaterialDialog() +{ + delete ui; +} diff --git a/extern/shiny/Editor/NewMaterialDialog.hpp b/extern/shiny/Editor/NewMaterialDialog.hpp new file mode 100644 index 0000000000..2a20bbb395 --- /dev/null +++ b/extern/shiny/Editor/NewMaterialDialog.hpp @@ -0,0 +1,22 @@ +#ifndef NEWMATERIALDIALOG_HPP +#define NEWMATERIALDIALOG_HPP + +#include + +namespace Ui { +class NewMaterialDialog; +} + +class NewMaterialDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NewMaterialDialog(QWidget *parent = 0); + ~NewMaterialDialog(); + +private: + Ui::NewMaterialDialog *ui; +}; + +#endif // NEWMATERIALDIALOG_HPP diff --git a/extern/shiny/Editor/PropertySortModel.cpp b/extern/shiny/Editor/PropertySortModel.cpp new file mode 100644 index 0000000000..637fe11b02 --- /dev/null +++ b/extern/shiny/Editor/PropertySortModel.cpp @@ -0,0 +1,35 @@ +#include "PropertySortModel.hpp" + +#include "Query.hpp" + +#include +sh::PropertySortModel::PropertySortModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +bool sh::PropertySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if (left.data(Qt::UserRole+1).toInt() != 0 && right.data(Qt::UserRole+1).toInt() != 0) + { + int sourceL = left.data(Qt::UserRole+1).toInt(); + int sourceR = right.data(Qt::UserRole+1).toInt(); + + if (sourceL > sourceR) + return true; + else if (sourceR > sourceL) + return false; + } + + int typeL = left.data(Qt::UserRole).toInt(); + int typeR = right.data(Qt::UserRole).toInt(); + + if (typeL > typeR) + return true; + else if (typeR > typeL) + return false; + + QString nameL = left.data().toString(); + QString nameR = right.data().toString(); + return nameL > nameR; +} diff --git a/extern/shiny/Editor/PropertySortModel.hpp b/extern/shiny/Editor/PropertySortModel.hpp new file mode 100644 index 0000000000..f96927764e --- /dev/null +++ b/extern/shiny/Editor/PropertySortModel.hpp @@ -0,0 +1,21 @@ +#ifndef SHINY_EDITOR_PROPERTYSORTMODEL_H +#define SHINY_EDITOR_PROPERTYSORTMODEL_H + +#include + +namespace sh +{ + + class PropertySortModel : public QSortFilterProxyModel + { + Q_OBJECT + + public: + PropertySortModel(QObject* parent); + protected: + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + }; + +} + +#endif diff --git a/extern/shiny/Editor/Query.cpp b/extern/shiny/Editor/Query.cpp new file mode 100644 index 0000000000..ccf07b62bc --- /dev/null +++ b/extern/shiny/Editor/Query.cpp @@ -0,0 +1,134 @@ +#include "Query.hpp" + +#include "../Main/Factory.hpp" + +namespace sh +{ + +void Query::execute() +{ + executeImpl(); + mDone = true; +} + +ConfigurationQuery::ConfigurationQuery(const std::string &name) + : mName(name) +{ +} + +void ConfigurationQuery::executeImpl() +{ + sh::Factory::getInstance().listConfigurationSettings(mName, mProperties); +} + +void MaterialQuery::executeImpl() +{ + sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(mName); + + if (instance->getParent()) + mParent = static_cast(instance->getParent())->getName(); + + // add the inherited properties + sh::PropertySetGet* parent = instance; + std::vector inheritedPropertiesVector; + while (parent->getParent()) + { + parent = parent->getParent(); + const sh::PropertyMap& parentProperties = parent->listProperties(); + + for (PropertyMap::const_iterator it = parentProperties.begin(); it != parentProperties.end(); ++it) + { + MaterialProperty::Source source = MaterialProperty::Inherited_Unchanged; + MaterialProperty::Type type = getType(it->first, parent->getProperty(it->first)); + mProperties[it->first] = MaterialProperty ( + retrieveValue(parent->getProperty(it->first), NULL).get(), + type, source); + inheritedPropertiesVector.push_back(it->first); + } + } + + // add our properties + const sh::PropertyMap& ourProperties = instance->listProperties(); + for (PropertyMap::const_iterator it = ourProperties.begin(); it != ourProperties.end(); ++it) + { + MaterialProperty::Source source = + (std::find(inheritedPropertiesVector.begin(), inheritedPropertiesVector.end(), it->first) + != inheritedPropertiesVector.end()) ? + MaterialProperty::Inherited_Changed : MaterialProperty::Normal; + MaterialProperty::Type type = getType(it->first, instance->getProperty(it->first)); + mProperties[it->first] = MaterialProperty ( + retrieveValue(instance->getProperty(it->first), NULL).get(), + type, source); + } + + std::vector* passes = instance->getPasses(); + for (std::vector::iterator it = passes->begin(); it != passes->end(); ++it) + { + mPasses.push_back(PassInfo()); + + const sh::PropertyMap& passProperties = it->listProperties(); + for (PropertyMap::const_iterator pit = passProperties.begin(); pit != passProperties.end(); ++pit) + { + PropertyValuePtr property = it->getProperty(pit->first); + MaterialProperty::Type type = getType(pit->first, property); + if (typeid(*property).name() == typeid(sh::LinkedValue).name()) + mPasses.back().mProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); + else + mPasses.back().mProperties[pit->first] = MaterialProperty( + retrieveValue(property, NULL).get(), type); + } + + const sh::PropertyMap& shaderProperties = it->mShaderProperties.listProperties(); + for (PropertyMap::const_iterator pit = shaderProperties.begin(); pit != shaderProperties.end(); ++pit) + { + PropertyValuePtr property = it->mShaderProperties.getProperty(pit->first); + MaterialProperty::Type type = getType(pit->first, property); + if (typeid(*property).name() == typeid(sh::LinkedValue).name()) + mPasses.back().mShaderProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type); + else + mPasses.back().mShaderProperties[pit->first] = MaterialProperty( + retrieveValue(property, NULL).get(), type); + } + + std::vector* texUnits = &it->mTexUnits; + for (std::vector::iterator tIt = texUnits->begin(); tIt != texUnits->end(); ++tIt) + { + mPasses.back().mTextureUnits.push_back(TextureUnitInfo()); + mPasses.back().mTextureUnits.back().mName = tIt->getName(); + const sh::PropertyMap& unitProperties = tIt->listProperties(); + for (PropertyMap::const_iterator pit = unitProperties.begin(); pit != unitProperties.end(); ++pit) + { + PropertyValuePtr property = tIt->getProperty(pit->first); + MaterialProperty::Type type = getType(pit->first, property); + if (typeid(*property).name() == typeid(sh::LinkedValue).name()) + mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( + "$" + property->_getStringValue(), MaterialProperty::Linked); + else + mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty( + retrieveValue(property, NULL).get(), type); + } + } + } +} + +MaterialProperty::Type MaterialQuery::getType(const std::string &key, PropertyValuePtr value) +{ + if (typeid(*value).name() == typeid(sh::LinkedValue).name()) + return MaterialProperty::Linked; + + if (key == "vertex_program" || key == "fragment_program") + return MaterialProperty::Shader; + + std::string valueStr = retrieveValue(value, NULL).get(); + + if (valueStr == "false" || valueStr == "true") + return MaterialProperty::Boolean; +} + +void MaterialPropertyQuery::executeImpl() +{ + sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName); + mValue = retrieveValue(m->getProperty(mPropertyName), m).get(); +} + +} diff --git a/extern/shiny/Editor/Query.hpp b/extern/shiny/Editor/Query.hpp new file mode 100644 index 0000000000..7aec684880 --- /dev/null +++ b/extern/shiny/Editor/Query.hpp @@ -0,0 +1,121 @@ +#ifndef SH_QUERY_H +#define SH_QUERY_H + +#include +#include +#include + +#include "../Main/PropertyBase.hpp" + +namespace sh +{ + +class Query +{ +public: + Query() + : mDone(false) {} + virtual ~Query(); + + void execute(); + + bool mDone; + +protected: + virtual void executeImpl() = 0; +}; + +class ConfigurationQuery : public Query +{ +public: + ConfigurationQuery(const std::string& name); + + std::map mProperties; +protected: + std::string mName; + virtual void executeImpl(); +}; + + +struct MaterialProperty +{ + + enum Type + { + Texture, + Color, + Boolean, + Shader, + Misc, + Linked, + Object // child object, i.e. pass, texture unit, shader properties + }; + + enum Source + { + Normal, + Inherited_Changed, + Inherited_Unchanged, + None // there is no property source (e.g. a pass, which does not have a name) + }; + + MaterialProperty() {} + MaterialProperty (const std::string& value, Type type, Source source=Normal) + : mValue(value), mType(type), mSource(source) {} + + std::string mValue; + Type mType; + Source mSource; +}; + + +struct TextureUnitInfo +{ + std::string mName; + std::map mProperties; +}; + +struct PassInfo +{ + std::map mShaderProperties; + + std::map mProperties; + std::vector mTextureUnits; +}; + +class MaterialQuery : public Query +{ +public: + MaterialQuery(const std::string& name) + : mName(name) {} + + std::string mParent; + std::vector mPasses; + std::map mProperties; + +protected: + std::string mName; + virtual void executeImpl(); + + MaterialProperty::Type getType (const std::string& key, PropertyValuePtr value); +}; + +class MaterialPropertyQuery : public Query +{ +public: + MaterialPropertyQuery(const std::string& name, const std::string& propertyName) + : mName(name), mPropertyName(propertyName) + { + } + + std::string mValue; + + std::string mName; + std::string mPropertyName; +protected: + virtual void executeImpl(); +}; + +} + +#endif diff --git a/extern/shiny/Editor/addpropertydialog.ui b/extern/shiny/Editor/addpropertydialog.ui new file mode 100644 index 0000000000..63de7d1415 --- /dev/null +++ b/extern/shiny/Editor/addpropertydialog.ui @@ -0,0 +1,118 @@ + + + AddPropertyDialog + + + + 0 + 0 + 257 + 133 + + + + Dialog + + + + + + + + + + + + + Property name + + + + + + + Editing widget + + + + + + + + Checkbox + + + + + Shader + + + + + Color + + + + + Texture + + + + + Other + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + AddPropertyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AddPropertyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/extern/shiny/Editor/mainwindow.ui b/extern/shiny/Editor/mainwindow.ui new file mode 100644 index 0000000000..b27c8357de --- /dev/null +++ b/extern/shiny/Editor/mainwindow.ui @@ -0,0 +1,420 @@ + + + MainWindow + + + + 0 + 0 + 647 + 512 + + + + MainWindow + + + + + + + 0 + + + + + + + Materials + + + + + + Qt::Horizontal + + + + + + + + + + Search + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + + + + + + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + 16 + 16 + + + + Qt::ToolButtonIconOnly + + + + + + + + + + + + + + Global settings + + + + + + + + + + Configurations + + + + + + Qt::Horizontal + + + + + + + + + + + 16 + 16 + + + + + + + + + + + + + + + + + + 16 + 16 + + + + + + + + + + + + + + Errors + + + + + + + + true + + + + + + + + 0 + 0 + + + + Clear + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 647 + 25 + + + + false + + + + File + + + + + + + Material + + + + + + + + + History + + + + + + + + + + + + + + Quit + + + + + + + + + + Save + + + Save all + + + + + + + + + + Delete + + + Delete selected material + + + + + Change parent... + + + + + + + + + + New + + + Create a new material + + + + + + + + + + Clone + + + Clone selected material + + + + + + + + + + Delete + + + Delete selected configuration + + + Del + + + + + + + + + + New + + + Create a new configuration + + + + + + + + + + Delete + + + Delete property + + + + + + + + + + Delete + + + Delete item + + + + + + + + + + New property + + + + + + + + + + Create pass + + + + + + + + + + Create texture unit + + + + + + sh::ColoredTabWidget + QTabWidget +
ColoredTabWidget.hpp
+ 1 +
+
+ + +
diff --git a/extern/shiny/Editor/newmaterialdialog.ui b/extern/shiny/Editor/newmaterialdialog.ui new file mode 100644 index 0000000000..f24561cf79 --- /dev/null +++ b/extern/shiny/Editor/newmaterialdialog.ui @@ -0,0 +1,98 @@ + + + NewMaterialDialog + + + + 0 + 0 + 385 + 198 + + + + Dialog + + + + + + + + Name + + + + + + + Parent material + + + + + + + + + + + + + File + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NewMaterialDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NewMaterialDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +