mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-05 05:07:48 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* RobloxSettingsDialog.cpp
|
||||
* Copyright (c) 2013 ROBLOX Corp. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "RobloxSettingsDialog.h"
|
||||
|
||||
// Qt Headers
|
||||
#include <QApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QSplitter>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
|
||||
// Roblox Headers
|
||||
#include "v8datamodel/GlobalSettings.h"
|
||||
#include "v8datamodel/Selection.h"
|
||||
#include "ReflectionMetaData.h"
|
||||
|
||||
// Roblox Studio Headers
|
||||
#include "RobloxCustomWidgets.h"
|
||||
#include "QtUtilities.h"
|
||||
#include "AuthoringSettings.h"
|
||||
|
||||
static const char* StudioSettings = "Studio";
|
||||
static const char* GeometrySetting = "RobloxSettingsDialog/Geometry";
|
||||
static const char* SplitterStateSetting = "RobloxSettingsDialog/SplitterState";
|
||||
|
||||
RobloxSettingsDialog::RobloxSettingsDialog(QWidget* parent)
|
||||
:QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint)
|
||||
{
|
||||
m_SettingsTypesTable = new QTableWidget(this);
|
||||
m_SettingsTree = new SelectionPropertyTree(this);
|
||||
|
||||
//m_SettingsTypesTable->setFrameStyle(QFrame::NoFrame);
|
||||
m_SettingsTypesTable->setColumnCount(1);
|
||||
QStringList headerLabels("Names");
|
||||
m_SettingsTypesTable->setHorizontalHeaderLabels(headerLabels);
|
||||
m_SettingsTypesTable->verticalHeader()->hide();
|
||||
m_SettingsTypesTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
|
||||
m_SettingsTypesTable->horizontalHeader()->setClickable(true);
|
||||
m_SettingsTypesTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
|
||||
m_SettingsTypesTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_SettingsTypesTable->setAlternatingRowColors(true);
|
||||
m_SettingsTypesTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
connect(m_SettingsTypesTable, SIGNAL(currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)), this, SLOT(onCategorySelected(QTableWidgetItem*, QTableWidgetItem*)));
|
||||
|
||||
//m_SettingsTree->setFrameStyle(QFrame::NoFrame);
|
||||
m_SettingsTree->setHeaderHidden(true);
|
||||
|
||||
m_hSplitter = new QSplitter(this);
|
||||
m_hSplitter->addWidget(m_SettingsTypesTable);
|
||||
m_hSplitter->addWidget(m_SettingsTree);
|
||||
|
||||
m_hSplitter->setCollapsible(0,false);
|
||||
m_hSplitter->setCollapsible(1,false);
|
||||
|
||||
// Add the Reset and close buttons
|
||||
QPushButton *closeButton = new QPushButton(tr("Close"));
|
||||
closeButton->setAutoDefault(false);
|
||||
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
|
||||
|
||||
QPushButton *resetButton = new QPushButton(tr("Reset All Settings"));
|
||||
resetButton->setAutoDefault(false);
|
||||
connect(resetButton, SIGNAL(clicked()), this, SLOT(onReset()));
|
||||
|
||||
QHBoxLayout *buttonsLayout = new QHBoxLayout;
|
||||
buttonsLayout->addWidget(resetButton, 1, Qt::AlignLeft);
|
||||
buttonsLayout->addWidget(closeButton, 1, Qt::AlignRight);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(m_hSplitter);
|
||||
layout->addLayout(buttonsLayout);
|
||||
setLayout(layout);
|
||||
|
||||
populate();
|
||||
|
||||
m_SettingsTypesTable->setMinimumWidth(200);
|
||||
m_SettingsTree->setMinimumWidth(400);
|
||||
m_SettingsTree->header()->resizeSection(0, 200);
|
||||
setMinimumWidth(600);
|
||||
setMinimumHeight(370);
|
||||
|
||||
QtUtilities::updateWindowTitle(this);
|
||||
|
||||
// restore window state
|
||||
QSettings settings;
|
||||
restoreGeometry(settings.value(GeometrySetting).toByteArray());
|
||||
|
||||
// restore splitter state
|
||||
QList<int> sizes;
|
||||
sizes.append(200);
|
||||
sizes.append(width() - sizes[0]);
|
||||
m_hSplitter->setSizes(sizes);
|
||||
m_hSplitter->restoreState(settings.value(SplitterStateSetting).toByteArray());
|
||||
}
|
||||
|
||||
RobloxSettingsDialog::~RobloxSettingsDialog()
|
||||
{
|
||||
// save window state
|
||||
QSettings settings;
|
||||
settings.setValue(GeometrySetting,saveGeometry());
|
||||
settings.setValue(SplitterStateSetting,m_hSplitter->saveState());
|
||||
}
|
||||
|
||||
void RobloxSettingsDialog::onReset()
|
||||
{
|
||||
static bool hasSeenWarning = false;
|
||||
|
||||
if ( !hasSeenWarning )
|
||||
{
|
||||
QMessageBox::information(
|
||||
this,
|
||||
"Reset Settings",
|
||||
"Resetting settings will not take effect until you restart ROBLOX" );
|
||||
hasSeenWarning = true;
|
||||
}
|
||||
|
||||
RBX::GlobalAdvancedSettings::singleton()->eraseSettingsStore();
|
||||
}
|
||||
|
||||
bool RobloxSettingsDialog::close()
|
||||
{
|
||||
static bool hasSeenWarning = false;
|
||||
|
||||
if ( !hasSeenWarning )
|
||||
{
|
||||
QMessageBox::information(
|
||||
this,
|
||||
"Save Changes",
|
||||
"Some setting changes will not take effect until you restart ROBLOX" );
|
||||
hasSeenWarning = true;
|
||||
}
|
||||
|
||||
RBX::GlobalAdvancedSettings::singleton()->saveState();
|
||||
|
||||
return QDialog::close();
|
||||
}
|
||||
|
||||
void RobloxSettingsDialog::populate()
|
||||
{
|
||||
boost::shared_ptr<RBX::Instance> container = RBX::shared_from(RBX::GlobalAdvancedSettings::singleton().get());
|
||||
if(!container)
|
||||
return;
|
||||
|
||||
m_descendantAddedConnection.disconnect();
|
||||
m_descendantRemovingConnection.disconnect();
|
||||
m_SettingsTypesTable->clearContents();
|
||||
|
||||
container->visitDescendants(boost::bind(&RobloxSettingsDialog::onDescendantAdded, this, _1));
|
||||
m_descendantAddedConnection = container->getOrCreateDescendantAddedSignal()->connect(boost::bind(&RobloxSettingsDialog::onDescendantAdded, this, _1));
|
||||
m_descendantRemovingConnection = container->getOrCreateDescendantRemovingSignal()->connect(boost::bind(&RobloxSettingsDialog::onDescendantRemoving, this, _1));
|
||||
|
||||
m_SettingsTypesTable->setSortingEnabled(true);
|
||||
m_SettingsTypesTable->horizontalHeader()->stretchLastSection();
|
||||
|
||||
// Set settings property tree selection
|
||||
RBX::Selection* sel = RBX::ServiceProvider::create<RBX::Selection>(RBX::GlobalAdvancedSettings::singleton().get());
|
||||
m_SettingsTree->setSelection(sel);
|
||||
|
||||
QList<QTableWidgetItem*> studioItems = m_SettingsTypesTable->findItems(StudioSettings,Qt::MatchExactly);
|
||||
if ( !studioItems.isEmpty() )
|
||||
m_SettingsTypesTable->setCurrentItem(studioItems[0]);
|
||||
}
|
||||
|
||||
void RobloxSettingsDialog::onDescendantAdded(boost::shared_ptr<RBX::Instance> child)
|
||||
{
|
||||
if(!child)
|
||||
return;
|
||||
|
||||
const RBX::Reflection::ClassDescriptor* pClassDescriptor = &child->getDescriptor();
|
||||
if(pClassDescriptor)
|
||||
{
|
||||
if(!hasProperties(pClassDescriptor))
|
||||
return;
|
||||
}
|
||||
|
||||
QString itemName(child->getName().c_str());
|
||||
SettingsItem* pWidgetItem = new SettingsItem(child, itemName);
|
||||
int row = m_SettingsTypesTable->rowCount();
|
||||
m_SettingsTypesTable->insertRow(row);
|
||||
m_SettingsTypesTable->setItem(row, 0, pWidgetItem);
|
||||
}
|
||||
|
||||
bool RobloxSettingsDialog::hasProperties(const RBX::Reflection::ClassDescriptor* pClassDescriptor)
|
||||
{
|
||||
if(!pClassDescriptor)
|
||||
return false;
|
||||
|
||||
bool retVal = false;
|
||||
RBX::Reflection::ClassDescriptor::ClassDescriptors::const_iterator iter = pClassDescriptor->derivedClasses_begin();
|
||||
for(; iter != pClassDescriptor->derivedClasses_end(); iter++)
|
||||
{
|
||||
RBX::Reflection::ClassDescriptor* pDerived = *iter;
|
||||
if(pDerived)
|
||||
retVal = hasProperties(pDerived);
|
||||
|
||||
if(retVal)
|
||||
break;
|
||||
}
|
||||
|
||||
if(!retVal)
|
||||
{
|
||||
RBX::Reflection::MemberDescriptorContainer<RBX::Reflection::PropertyDescriptor>::Collection::const_iterator iter = pClassDescriptor->begin<RBX::Reflection::PropertyDescriptor>();
|
||||
for(; iter != pClassDescriptor->end<RBX::Reflection::PropertyDescriptor>(); iter++)
|
||||
{
|
||||
const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor = *iter;
|
||||
if(pPropertyDescriptor)
|
||||
{
|
||||
if ( pPropertyDescriptor->owner != *pClassDescriptor )
|
||||
continue;
|
||||
|
||||
if ( !pPropertyDescriptor->isPublic() || pPropertyDescriptor->security != RBX::Security::None )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RBX::Reflection::Metadata::Member* pMemeber = RBX::Reflection::Metadata::Reflection::singleton()->get(*pPropertyDescriptor);
|
||||
if(RBX::Reflection::Metadata::Item::isDeprecated(pMemeber, *pPropertyDescriptor))
|
||||
continue;
|
||||
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void RobloxSettingsDialog::onDescendantRemoving(boost::shared_ptr<RBX::Instance> child)
|
||||
{
|
||||
if(!child)
|
||||
return;
|
||||
|
||||
QString itemName(child->getName().c_str());
|
||||
QList<QTableWidgetItem *> tableItems = m_SettingsTypesTable->findItems(itemName, Qt::MatchExactly);
|
||||
if(tableItems.empty())
|
||||
return;
|
||||
QTableWidgetItem* item = tableItems[0];
|
||||
if(item != NULL)
|
||||
m_SettingsTypesTable->removeRow(item->row());
|
||||
}
|
||||
|
||||
void RobloxSettingsDialog::onCategorySelected(QTableWidgetItem* current, QTableWidgetItem* previous)
|
||||
{
|
||||
if(!current)
|
||||
return;
|
||||
|
||||
SettingsItem* item = dynamic_cast<SettingsItem*>(current);
|
||||
if(!item)
|
||||
return;
|
||||
|
||||
RBX::Selection* sel = m_SettingsTree->getSelection();
|
||||
if(!sel)
|
||||
return;
|
||||
|
||||
sel->clearSelection();
|
||||
sel->addToSelection(item->getInstance().get());
|
||||
}
|
||||
|
||||
|
||||
SelectionPropertyTree::SelectionPropertyTree(QWidget* parent)
|
||||
: PropertyTreeWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SelectionPropertyTree::~SelectionPropertyTree()
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
// On Mac, intermittent crash during deletion of GlobalAdvancedSetting requires us to explictly remove selection (if any)
|
||||
if (m_selection)
|
||||
m_selection->clearSelection();
|
||||
#endif
|
||||
setSelection(NULL);
|
||||
}
|
||||
|
||||
void SelectionPropertyTree::addSelectionInstance(boost::shared_ptr<RBX::Instance> pInstance)
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
|
||||
m_selectedInstances.push_back(pInstance.get());
|
||||
addInstance(pInstance.get());
|
||||
}
|
||||
|
||||
void SelectionPropertyTree::removeSelectionInstance(boost::shared_ptr<RBX::Instance> pInstance)
|
||||
{
|
||||
if (!pInstance)
|
||||
return;
|
||||
|
||||
InstanceList::iterator iter = std::find(m_selectedInstances.begin(), m_selectedInstances.end(), pInstance.get());
|
||||
if (iter != m_selectedInstances.end())
|
||||
m_selectedInstances.erase(iter);
|
||||
removeInstance(pInstance.get());
|
||||
}
|
||||
|
||||
|
||||
void SelectionPropertyTree::setSelection(RBX::Selection* value)
|
||||
{
|
||||
m_selectionChangedConnection.disconnect();
|
||||
reinitialize();
|
||||
m_selectedInstances.clear();
|
||||
|
||||
m_selection = shared_from(value);
|
||||
if (m_selection)
|
||||
{
|
||||
std::for_each(m_selection->begin(), m_selection->end(), boost::bind(&SelectionPropertyTree::addSelectionInstance, this, _1));
|
||||
m_selectionChangedConnection = m_selection->selectionChanged.connect(boost::bind(&SelectionPropertyTree::onSelectionChanged, this, _1));
|
||||
}
|
||||
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void SelectionPropertyTree::onSelectionChanged(const RBX::SelectionChanged& evt)
|
||||
{
|
||||
QMutexLocker lock(&m_propertyWidgetMutex);
|
||||
if (evt.addedItem)
|
||||
{
|
||||
static bool hasShownWarning = false;
|
||||
|
||||
if ( evt.addedItem->getName() != StudioSettings && !hasShownWarning )
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this,
|
||||
"Warning",
|
||||
"<p>Changing settings may make ROBLOX unstable.</p>"
|
||||
"<p>We recommend that you don't change any non-Studio settings "
|
||||
"unless instructed to do so by a ROBLOX engineer.</p>" );
|
||||
hasShownWarning = true;
|
||||
}
|
||||
|
||||
addSelectionInstance(evt.addedItem);
|
||||
}
|
||||
if (evt.removedItem)
|
||||
removeSelectionInstance(evt.removedItem);
|
||||
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void SelectionPropertyTree::requestUpdate()
|
||||
{
|
||||
QApplication::postEvent(this, new RobloxCustomEvent(PROPERTY_WIDGET_UPDATE));
|
||||
}
|
||||
|
||||
void SelectionPropertyTree::initProperty(const RBX::Reflection::ClassDescriptor* pClassDescriptor,
|
||||
const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor)
|
||||
{
|
||||
if (!pPropertyDescriptor)
|
||||
return;
|
||||
|
||||
// Filter Instance properties
|
||||
if (pPropertyDescriptor->owner != RBX::Instance::classDescriptor())
|
||||
{
|
||||
PropertyTreeWidget::initProperty(pClassDescriptor, pPropertyDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsItem::SettingsItem(boost::shared_ptr<RBX::Instance> inst, QString name)
|
||||
: QTableWidgetItem(name)
|
||||
, m_instance(inst)
|
||||
{}
|
||||
Reference in New Issue
Block a user