mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
3435 lines
98 KiB
C++
3435 lines
98 KiB
C++
/**
|
|
* PropertyItems.cpp
|
|
* Copyright (c) 2013 ROBLOX Corp. All Rights Reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "PropertyItems.h"
|
|
|
|
// Qt Headers
|
|
#include <QLineEdit>
|
|
#include <QDoubleSpinBox>
|
|
#include <QComboBox>
|
|
#include <QColorDialog>
|
|
#include <QFontDialog>
|
|
#include <QFileDialog>
|
|
#include <QMouseEvent>
|
|
#include <QApplication>
|
|
#include <QDesktopWidget>
|
|
#include <QPainter>
|
|
#include <QSettings>
|
|
#include <QPixmapCache>
|
|
|
|
// 3rd Party Headers
|
|
#include "G3D/Vector3.h"
|
|
|
|
// Roblox Headers
|
|
#include "v8datamodel/DataModel.h"
|
|
#include "v8datamodel/ChangeHistory.h"
|
|
#include "v8datamodel/ContentProvider.h"
|
|
#include "v8datamodel/ModelInstance.h"
|
|
#include "v8datamodel/Selection.h"
|
|
#include "v8datamodel/PartInstance.h"
|
|
#include "v8datamodel/PartOperation.h"
|
|
#include "v8datamodel/Workspace.h"
|
|
#include "util/ScopedAssign.h"
|
|
#include "util/Faces.h"
|
|
#include "util/UDim.h"
|
|
#include "util/Sound.h"
|
|
#include "util/TextureId.h"
|
|
#include "util/AnimationId.h"
|
|
#include "util/MeshId.h"
|
|
#include "util/BrickColor.h"
|
|
#include "util/PhysicalProperties.h"
|
|
#include "reflection/reflection.h"
|
|
#include "tool/ToolsArrow.h"
|
|
#include "reflection/Type.h"
|
|
#include "v8datamodel/NumberSequence.h"
|
|
#include "v8datamodel/NumberRange.h"
|
|
#include "v8datamodel/ColorSequence.h"
|
|
#include "v8datamodel/Workspace.h"
|
|
#include "v8world/MaterialProperties.h"
|
|
|
|
// Roblox Studio Headers
|
|
#include "RobloxPropertyWidget.h"
|
|
#include "RobloxCustomWidgets.h"
|
|
#include "ReflectionMetadata.h"
|
|
#include "QtUtilities.h"
|
|
#include "RobloxMainWindow.h"
|
|
#include "UpdateUIManager.h"
|
|
#include "RobloxSettings.h"
|
|
#include "RobloxGameExplorer.h"
|
|
#include "SplineEditor.h"
|
|
#include "RobloxDocManager.h"
|
|
#include "RobloxIDEDoc.h"
|
|
|
|
//utility functions to create icons
|
|
static QIcon getCheckBox(int value, bool readOnly);
|
|
static QIcon getColorIcon(const QColor &color);
|
|
|
|
//formatting code from Client/Roblox/PropGrid.cpp
|
|
static void trimTrailing0s(QString& s);
|
|
static QString format(double f);
|
|
|
|
FASTFLAG(GameExplorerImagesEnabled)
|
|
FASTFLAG(StudioPropertyCompareOriginalVals)
|
|
FASTFLAGVARIABLE(StudioPropertyErrorOutput, false)
|
|
FASTFLAGVARIABLE(AnimationIdIsContentPropertyItem, false)
|
|
FASTFLAGVARIABLE(FixColorSettingsCancel, false)
|
|
FASTFLAGVARIABLE(TextFieldUTF8, false)
|
|
DYNAMIC_FASTFLAG(MaterialPropertiesEnabled)
|
|
FASTFLAG(CSGPhysicsLevelOfDetailEnabled)
|
|
|
|
static const char* kLoadStringEnabledDialogDisabled = "LoadStringEnabledDialogDisabled";
|
|
|
|
static const double m_SliderDivisor = 100.0f;
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// StringPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class StringPropertyItem: public PropertyItem
|
|
{
|
|
public:
|
|
StringPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
std::string strVal = m_variantValue.get<std::string>();
|
|
|
|
if (FFlag::TextFieldUTF8)
|
|
return QString::fromUtf8(strVal.c_str());
|
|
else
|
|
return strVal.c_str();
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
if (!pInstance || !m_pPropertyDescriptor)
|
|
return;
|
|
|
|
setVariantValue(m_pPropertyDescriptor->getStringValue(pInstance));
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
if (!pInstance || !m_pPropertyDescriptor)
|
|
return;
|
|
|
|
std::string strVal = m_variantValue.get<std::string>();
|
|
m_pPropertyDescriptor->setStringValue(pInstance, strVal);
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
pLineEdit->setMaxLength(131072); // 128k
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
if (FFlag::TextFieldUTF8)
|
|
{
|
|
QByteArray ba = pLineEdit->text().toUtf8();
|
|
setVariantValue(std::string(ba.constData(), ba.size()));
|
|
}
|
|
else
|
|
{
|
|
setVariantValue(pLineEdit->text().toStdString());
|
|
}
|
|
|
|
commitModification();
|
|
}
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// BoolPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class BoolPropertyItem:public PropertyItem
|
|
{
|
|
int m_isChecked;
|
|
public:
|
|
BoolPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_isChecked(0)
|
|
{
|
|
setIcon(1, getCheckBox(m_isChecked, isReadOnly()));
|
|
}
|
|
|
|
QString getTextValue(const RBX::Instance*)
|
|
{ return QString("");}
|
|
|
|
void toggleState()
|
|
{
|
|
m_isChecked = !m_isChecked;
|
|
setIcon(1, getCheckBox(m_isChecked, isReadOnly()));
|
|
|
|
setVariantValue((bool)m_isChecked);
|
|
commitModification();
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
|
|
m_isChecked = m_variantValue.get<bool>();
|
|
setIcon(1, getCheckBox(m_isChecked, isReadOnly()));
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
m_pPropertyDescriptor->setVariant(pInstance, m_variantValue.get<bool>());
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = PropertyItem::compareInstanceValues(pPreviousInstance, pCurrentInstance);
|
|
if (!result)
|
|
{
|
|
m_isChecked = -1;
|
|
setIcon(1, getCheckBox(m_isChecked, isReadOnly()));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool editorEvent(QEvent * pEvent)
|
|
{
|
|
if (!m_pPropertyDescriptor->isReadOnly() && (pEvent->type() == QEvent::MouseButtonRelease))
|
|
{
|
|
QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);
|
|
if (pMouseEvent && (pMouseEvent->button() & Qt::LeftButton))
|
|
{
|
|
if (canModifyValue())
|
|
toggleState();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool isReadOnly()
|
|
{ return m_pPropertyDescriptor ? m_pPropertyDescriptor->isReadOnly() : true; }
|
|
|
|
bool canModifyValue()
|
|
{
|
|
// TODO: make this a generic function if we have to add some more properties with a message box
|
|
if (!m_isChecked && (strcmp(m_pPropertyDescriptor->name.c_str(), "LoadStringEnabled") == 0))
|
|
{
|
|
if (!RobloxSettings().value(kLoadStringEnabledDialogDisabled, false).toBool())
|
|
{
|
|
QtUtilities::RBXConfirmationMessageBox msgBox("Activating 'LoadStringEnabled' property might make your game vulnerable to exploits \
|
|
(for more information\
|
|
<a href=\"http://wiki.roblox.com/index.php?title=Security#LoadStringEnabled\">click here</a>).\
|
|
Are you sure you want to enable it?");
|
|
|
|
msgBox.setMinimumWidth(410);
|
|
msgBox.setMinimumHeight(90);
|
|
//show message box
|
|
msgBox.exec();
|
|
if (msgBox.getCheckBoxState())
|
|
RobloxSettings().setValue(kLoadStringEnabledDialogDisabled, true);
|
|
return msgBox.getClickedYes();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// IntPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class IntPropertyItem: public PropertyItem
|
|
{
|
|
public:
|
|
IntPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
IntPropertyItem(PropertyItem *pParentItem, const QString &name)
|
|
: PropertyItem(pParentItem, name)
|
|
{
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
int val = m_variantValue.get<int>();
|
|
return QString::number(val);
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QSpinBox *pSpinBox = new QSpinBox(parent);
|
|
pSpinBox->setGeometry(option.rect);
|
|
pSpinBox->setMinimum(INT_MIN);
|
|
pSpinBox->setMaximum(INT_MAX);
|
|
pSpinBox->setFrame(false);
|
|
return pSpinBox;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QSpinBox *pSpinBox = dynamic_cast<QSpinBox *>(editor);
|
|
if (!pSpinBox)
|
|
return;
|
|
|
|
pSpinBox->setValue(text(1).toInt());
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QSpinBox *pSpinBox = dynamic_cast<QSpinBox *>(editor);
|
|
if (!pSpinBox)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pSpinBox->cleanText() != text(1))
|
|
{
|
|
setVariantValue(pSpinBox->value());
|
|
commitModification();
|
|
}
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// DoublePropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
DoublePropertyItem::DoublePropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_SpinBox(NULL)
|
|
, m_Slider(NULL)
|
|
{
|
|
}
|
|
|
|
DoublePropertyItem::DoublePropertyItem(PropertyItem *pParentItem, const QString &name)
|
|
: PropertyItem(pParentItem, name)
|
|
, m_SpinBox(NULL)
|
|
, m_Slider(NULL)
|
|
{
|
|
}
|
|
|
|
QString DoublePropertyItem::getTextValue()
|
|
{
|
|
double val = m_variantValue.get<double>();
|
|
return format(val);
|
|
}
|
|
|
|
void DoublePropertyItem::onSliderChanged(int value)
|
|
{
|
|
setVariantValue(value / m_SliderDivisor);
|
|
commitModification(false);
|
|
updateSpinBox();
|
|
}
|
|
|
|
void DoublePropertyItem::onSpinBoxChanged()
|
|
{
|
|
setVariantValue(m_SpinBox->value());
|
|
commitModification(false);
|
|
updateSlider();
|
|
}
|
|
|
|
void DoublePropertyItem::onSliderReleased()
|
|
{
|
|
commitModification();
|
|
}
|
|
|
|
void DoublePropertyItem::updateSpinBox()
|
|
{
|
|
if (m_SpinBox)
|
|
{
|
|
m_SpinBox->blockSignals(true);
|
|
m_SpinBox->setValue(m_variantValue.get<double>());
|
|
m_SpinBox->blockSignals(false);
|
|
}
|
|
}
|
|
|
|
void DoublePropertyItem::updateSlider()
|
|
{
|
|
if (m_Slider)
|
|
{
|
|
m_Slider->blockSignals(true);
|
|
m_Slider->setValue(m_variantValue.get<double>() * m_SliderDivisor);
|
|
m_Slider->blockSignals(false);
|
|
}
|
|
}
|
|
|
|
QWidget* DoublePropertyItem::createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
double minimum = 0;
|
|
double maximum = 0;
|
|
|
|
if (m_pPropertyDescriptor)
|
|
{
|
|
if (RBX::Reflection::Metadata::Item* metadata = RBX::Reflection::Metadata::Reflection::singleton()->get(*m_pPropertyDescriptor))
|
|
{
|
|
minimum = metadata->minimum;
|
|
maximum = metadata->maximum;
|
|
}
|
|
}
|
|
|
|
if (minimum != maximum)
|
|
{
|
|
QWidget* widget = new QWidget(parent);
|
|
QHBoxLayout* layout = new QHBoxLayout;
|
|
|
|
layout->setContentsMargins(0,0,0,0);
|
|
layout->setSpacing(0);
|
|
|
|
m_Slider = new QSlider(Qt::Horizontal);
|
|
m_Slider->setStyleSheet(STRINGIFY(QSlider{ background: white; } ));
|
|
m_Slider->setRange(minimum * m_SliderDivisor, maximum * m_SliderDivisor);
|
|
m_Slider->setFocusPolicy(Qt::WheelFocus);
|
|
m_Slider->installEventFilter(this);
|
|
m_Slider->setValue(m_variantValue.get<double>() * m_SliderDivisor);
|
|
|
|
m_SpinBox = new QDoubleSpinBox(widget);
|
|
m_SpinBox->setSingleStep(0.01f);
|
|
m_SpinBox->setRange(minimum, maximum);
|
|
m_SpinBox->setDecimals(3);
|
|
m_SpinBox->setFocusPolicy(Qt::WheelFocus);
|
|
m_SpinBox->installEventFilter(this);
|
|
m_SpinBox->setValue(m_variantValue.get<double>());
|
|
|
|
layout->addWidget(m_SpinBox);
|
|
layout->addWidget(m_Slider);
|
|
|
|
widget->setLayout(layout);
|
|
widget->setGeometry(option.rect);
|
|
|
|
connect(m_Slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
|
|
connect(m_Slider, SIGNAL(sliderReleased()), this, SLOT(onSliderReleased()));
|
|
connect(m_SpinBox, SIGNAL(valueChanged(double)), this, SLOT(onSpinBoxChanged()));
|
|
|
|
widget->setFocusProxy(m_SpinBox);
|
|
|
|
return widget;
|
|
}
|
|
|
|
DoubleSpinBoxWidget *pSpinBoxWidget = new DoubleSpinBoxWidget(parent);
|
|
pSpinBoxWidget->setGeometry(option.rect);
|
|
pSpinBoxWidget->setSingleStep(1);
|
|
pSpinBoxWidget->setMinimum(-DBL_MAX);
|
|
pSpinBoxWidget->setMaximum(DBL_MAX);
|
|
pSpinBoxWidget->setFrame(false);
|
|
pSpinBoxWidget->setDecimals(FFlag::StudioPropertyErrorOutput ? 10 : 3);
|
|
return pSpinBoxWidget;
|
|
}
|
|
|
|
void DoublePropertyItem::setEditorData(QWidget *editor)
|
|
{
|
|
DoubleSpinBoxWidget *pSpinBox = dynamic_cast<DoubleSpinBoxWidget *>(editor);
|
|
if (!pSpinBox)
|
|
return;
|
|
|
|
pSpinBox->setValue(text(1).toDouble());
|
|
}
|
|
|
|
void DoublePropertyItem::setModelData(QWidget *editor)
|
|
{
|
|
if (m_Slider)
|
|
{
|
|
if (m_SpinBox)
|
|
{
|
|
setVariantValue(m_SpinBox->value());
|
|
commitModification();
|
|
|
|
m_SpinBox->removeEventFilter(this);
|
|
m_SpinBox = NULL;
|
|
}
|
|
|
|
m_Slider->removeEventFilter(this);
|
|
m_Slider = NULL;
|
|
}
|
|
else
|
|
{
|
|
DoubleSpinBoxWidget *pSpinBox = dynamic_cast<DoubleSpinBoxWidget *>(editor);
|
|
if (!pSpinBox)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pSpinBox->cleanText() != text(1))
|
|
{
|
|
setVariantValue(pSpinBox->value());
|
|
commitModification();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoublePropertyItem::setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
if (FFlag::StudioPropertyErrorOutput)
|
|
{
|
|
QString str1 = format(value.get<double>());
|
|
QString str2 = QString("%1").arg(value.get<double>());
|
|
trimTrailing0s(str2);
|
|
|
|
if (str1 != str2)
|
|
{
|
|
m_variantValue = RBX::Reflection::Variant(str1.toDouble());
|
|
}
|
|
else
|
|
{
|
|
m_variantValue = value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_variantValue = value;
|
|
}
|
|
|
|
//check if the value will be changed
|
|
setTextValue(getTextValue());
|
|
}
|
|
|
|
bool DoublePropertyItem::eventFilter(QObject * obj, QEvent * evt)
|
|
{
|
|
if (evt->type() == QEvent::FocusIn || evt->type() == QEvent::FocusOut)
|
|
{
|
|
QWidget* focus = QApplication::focusWidget();
|
|
|
|
if (focus != m_Slider && focus != m_SpinBox)
|
|
{
|
|
QWidget* parentEditor = static_cast<QWidget*>(m_SpinBox->parent());
|
|
setModelData(parentEditor);
|
|
getTreeWidget()->closeEditor(parentEditor, QAbstractItemDelegate::NoHint);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// EnumPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class EnumPropertyItem: public PropertyItem
|
|
{
|
|
typedef QMap<QString, int> EnumItems;
|
|
EnumItems m_enumItems;
|
|
|
|
bool m_bUpdateInProgress;
|
|
|
|
static bool shouldDisplayEnumItem(const RBX::Reflection::EnumDescriptor::Item* item)
|
|
{
|
|
RBX::Reflection::Metadata::EnumItem* m = RBX::Reflection::Metadata::Reflection::singleton()->get(*item);
|
|
|
|
if (m && !m->isBrowsable())
|
|
return false;
|
|
|
|
return !RBX::Reflection::Metadata::Item::isDeprecated(m, *item);
|
|
}
|
|
|
|
public:
|
|
EnumPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_bUpdateInProgress(false)
|
|
{
|
|
const RBX::Reflection::EnumPropertyDescriptor* pEnumDesc = dynamic_cast<const RBX::Reflection::EnumPropertyDescriptor*>(pPropertyDescriptor);
|
|
if (pEnumDesc)
|
|
{
|
|
std::vector<const RBX::Reflection::EnumDescriptor::Item* >::const_iterator curIter, endIter;
|
|
curIter = pEnumDesc->enumDescriptor.begin();
|
|
endIter = pEnumDesc->enumDescriptor.end();
|
|
while (curIter!=endIter)
|
|
{
|
|
if (shouldDisplayEnumItem(*curIter))
|
|
m_enumItems[(*curIter)->name.c_str()] = (*curIter)->value;
|
|
|
|
++curIter;
|
|
}
|
|
}
|
|
}
|
|
|
|
//somehow variant value got from m_pPropertyDescriptor throws an exception while casting (so setting it explicitly)
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
const RBX::Reflection::EnumPropertyDescriptor* pEnumDesc = dynamic_cast<const RBX::Reflection::EnumPropertyDescriptor*>(m_pPropertyDescriptor);
|
|
if (pEnumDesc)
|
|
setVariantValue(pEnumDesc->getEnumValue(pInstance));
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
const RBX::Reflection::EnumPropertyDescriptor* pEnumDesc = dynamic_cast<const RBX::Reflection::EnumPropertyDescriptor*>(m_pPropertyDescriptor);
|
|
if (pEnumDesc)
|
|
pEnumDesc->setEnumValue(pInstance, m_variantValue.get<int>());
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
int val = m_variantValue.get<int>();
|
|
return m_enumItems.key(val);
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QComboBox *pComboBox = new QComboBox(parent);
|
|
pComboBox->setGeometry(option.rect);
|
|
pComboBox->setFrame(UpdateUIManager::Instance().getMainWindow().isRibbonStyle());
|
|
|
|
pComboBox->addItems(m_enumItems.keys());
|
|
|
|
return pComboBox;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QComboBox *pComboBox = dynamic_cast<QComboBox *>(editor);
|
|
if (!pComboBox)
|
|
return;
|
|
|
|
//set current value in the combo
|
|
int index = pComboBox->findText(text(1));
|
|
pComboBox->setCurrentIndex(index < 0 ? 0 : index);
|
|
|
|
SignalConnector *pSignalConnector = new SignalConnector(this);
|
|
pSignalConnector->setParent(pComboBox);
|
|
|
|
//connect with the required signal
|
|
pSignalConnector->connectSignalArg1(pComboBox, SIGNAL(currentIndexChanged(const QString &)));
|
|
}
|
|
|
|
void onEvent(const QObject *, const QString &arg)
|
|
{
|
|
if (m_bUpdateInProgress)
|
|
return;
|
|
|
|
RBX::ScopedAssign<bool> ignoreCommitModif(m_bUpdateInProgress, true);
|
|
|
|
if ( !m_enumItems.contains(arg) )
|
|
return;
|
|
setVariantValue(m_enumItems[arg]);
|
|
commitModification();
|
|
}
|
|
|
|
bool update()
|
|
{
|
|
RBX::ScopedAssign<bool> ignoreCommitModif(m_bUpdateInProgress, true);
|
|
return PropertyItem::update();
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// BrickColorPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
#define PROP_BUTTON_SIZE 20
|
|
|
|
BrickColorPropertyItem::BrickColorPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_pPopupLaunchEditor(NULL)
|
|
{
|
|
}
|
|
|
|
QString BrickColorPropertyItem::getTextValue()
|
|
{
|
|
RBX::BrickColor color = m_variantValue.get<RBX::BrickColor>();
|
|
return color.name().c_str();
|
|
}
|
|
|
|
void BrickColorPropertyItem::updateIcon()
|
|
{
|
|
if (m_isMultiValued)
|
|
{
|
|
setIcon(1, QIcon());
|
|
}
|
|
else
|
|
{
|
|
RBX::BrickColor rbxColor = m_variantValue.get<RBX::BrickColor>();
|
|
G3D::Color4uint8 colorToConvert = rbxColor.color4uint8();
|
|
QColor qtColor(colorToConvert.r, colorToConvert.g, colorToConvert.b, colorToConvert.a);
|
|
setIcon(1, getColorIcon(qtColor));
|
|
}
|
|
}
|
|
|
|
bool BrickColorPropertyItem::update()
|
|
{
|
|
if (!PropertyItem::update())
|
|
return false;
|
|
|
|
updateIcon();
|
|
|
|
return true;
|
|
}
|
|
|
|
QWidget* BrickColorPropertyItem::createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
m_pPopupLaunchEditor = new PopupLaunchEditor(this, parent, icon(1), text(1), PROP_BUTTON_SIZE);
|
|
m_pPopupLaunchEditor->setGeometry(option.rect);
|
|
m_pPopupLaunchEditor->setAutoFillBackground(true);
|
|
|
|
return m_pPopupLaunchEditor;
|
|
}
|
|
|
|
bool BrickColorPropertyItem::customLaunchEditorHook(QMouseEvent* event)
|
|
{
|
|
getTreeWidget()->storeOriginalValues(this);
|
|
buttonClicked();
|
|
return true;
|
|
}
|
|
|
|
void BrickColorPropertyItem::buttonClicked(const QString& buttonName)
|
|
{
|
|
RBX::BrickColor color = m_variantValue.get<RBX::BrickColor>();
|
|
|
|
ColorPickerFrame *pPickerFrame = new ColorPickerFrame(m_pPopupLaunchEditor);
|
|
|
|
pPickerFrame->setSelectedItem(color.asInt());
|
|
pPickerFrame->move(computePopupLocation(pPickerFrame->size()));
|
|
pPickerFrame->show();
|
|
|
|
QString previousColor = text(1);
|
|
|
|
connect(pPickerFrame, SIGNAL(currentBrickColorChanged(int)), this, SLOT(updatePropertyValue(int)));
|
|
|
|
QEventLoop* eventLoop = new QEventLoop(pPickerFrame);
|
|
pPickerFrame->setEventLoop(eventLoop);
|
|
eventLoop->exec();
|
|
|
|
getTreeWidget()->resetPropertyCallback();
|
|
|
|
int selectedColor = pPickerFrame->getSelectedItem();
|
|
if (selectedColor != -1 && ( (selectedColor != color.asInt()) ||
|
|
(FFlag::StudioPropertyCompareOriginalVals && !getTreeWidget()->hasSameOriginalValues())))
|
|
{
|
|
setVariantValue(RBX::BrickColor(selectedColor));
|
|
commitModification();
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
else
|
|
{
|
|
getTreeWidget()->restoreOriginalValues(this);
|
|
getTreeWidget()->resetOriginalValues();
|
|
}
|
|
|
|
m_pPopupLaunchEditor = NULL;
|
|
}
|
|
|
|
void BrickColorPropertyItem::updatePropertyValueQColor(QColor selectedColor)
|
|
{
|
|
if (!selectedColor.isValid())
|
|
{
|
|
getTreeWidget()->restoreOriginalValues(this);
|
|
return;
|
|
}
|
|
|
|
RBX::BrickColor brickColor = RBX::BrickColor::closest(G3D::Color3::fromARGB(selectedColor.rgba()));
|
|
|
|
setVariantValue(brickColor);
|
|
commitModification(false);
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
|
|
void BrickColorPropertyItem::updatePropertyValue(int selectedColor)
|
|
{
|
|
if (selectedColor == -1)
|
|
return;
|
|
|
|
RBX::BrickColor brickColor(selectedColor);
|
|
|
|
setVariantValue(brickColor);
|
|
commitModification(false);
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// ColorPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
ColorPropertyItem::ColorPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_pPopupLaunchEditor(NULL)
|
|
, m_pProxyLineEdit(NULL)
|
|
{
|
|
}
|
|
|
|
ColorPropertyItem::ColorPropertyItem(PropertyItem* parent, const QString& name)
|
|
: PropertyItem(parent, name)
|
|
, m_pPopupLaunchEditor(NULL)
|
|
, m_pProxyLineEdit(NULL)
|
|
{
|
|
}
|
|
|
|
QString ColorPropertyItem::getTextValue()
|
|
{
|
|
G3D::Color3 color = m_variantValue.get<G3D::Color3>();
|
|
return QString("[%1, %2, %3]").arg((int)(color.r *255)).arg((int)(color.g *255)).arg((int)(color.b *255));
|
|
}
|
|
|
|
void ColorPropertyItem::updateIcon()
|
|
{
|
|
if (m_isMultiValued)
|
|
{
|
|
setIcon(1, QIcon());
|
|
}
|
|
else
|
|
{
|
|
G3D::Color3 color = m_variantValue.get<G3D::Color3>();
|
|
QColor qtColor(color.r *255, color.g *255, color.b *255);
|
|
setIcon(1, getColorIcon(qtColor));
|
|
}
|
|
}
|
|
|
|
bool ColorPropertyItem::update()
|
|
{
|
|
if (!PropertyItem::update())
|
|
return false;
|
|
|
|
updateIcon();
|
|
|
|
return true;
|
|
}
|
|
|
|
QWidget* ColorPropertyItem::createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
m_pProxyLineEdit = new QLineEdit();
|
|
m_pProxyLineEdit->setFrame(false);
|
|
|
|
m_pPopupLaunchEditor = new PopupLaunchEditor(this, parent, icon(1), text(1), PROP_BUTTON_SIZE, m_pProxyLineEdit);
|
|
m_pPopupLaunchEditor->setGeometry(option.rect);
|
|
m_pPopupLaunchEditor->setAutoFillBackground(true);
|
|
|
|
return m_pPopupLaunchEditor;
|
|
}
|
|
|
|
void ColorPropertyItem::setEditorData(QWidget *editor)
|
|
{
|
|
m_pProxyLineEdit->setParent(m_pPopupLaunchEditor);
|
|
|
|
G3D::Color3 color = m_variantValue.get<G3D::Color3>();
|
|
m_pProxyLineEdit->setText(QString("%1, %2, %3").arg((int)(color.r *255)).arg((int)(color.g *255)).arg((int)(color.b *255)));
|
|
}
|
|
|
|
bool ColorPropertyItem::customLaunchEditorHook(QMouseEvent* event)
|
|
{
|
|
getTreeWidget()->storeOriginalValues(this);
|
|
int sectionPos = treeWidget()->header()->sectionViewportPosition(1);
|
|
if (sectionPos <= event->pos().x() && sectionPos + popupLauncherButtonSize() >= event->pos().x())
|
|
{
|
|
buttonClicked();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ColorPropertyItem::buttonClicked(const QString& buttonName)
|
|
{
|
|
// restore the custom colors the user has set
|
|
QSettings settings;
|
|
for ( int i = 0 ; i < QColorDialog::customCount() ; i++ )
|
|
{
|
|
QRgb c = settings.value("CustomColor/" + QString::number(i),-1).toInt();
|
|
QColorDialog::setCustomColor(i,c);
|
|
}
|
|
|
|
// set the original color in the color dialog
|
|
G3D::Color3 originalColor = m_variantValue.get<G3D::Color3>();
|
|
QColor originalQColor(originalColor.r * 255,originalColor.g * 255,originalColor.b * 255);
|
|
QColorDialog colorDialog(originalQColor,getTreeWidget());
|
|
|
|
connect(&colorDialog, SIGNAL(currentColorChanged(QColor)), this, SLOT(updatePropertyValue(QColor)));
|
|
|
|
if (colorDialog.exec())
|
|
{
|
|
getTreeWidget()->resetPropertyCallback();
|
|
|
|
QColor selectedColor = colorDialog.selectedColor();
|
|
|
|
G3D::Color3 color = G3D::Color3::fromARGB(selectedColor.rgba());
|
|
setVariantValue(color);
|
|
commitModification();
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
|
|
// save the custom colors the user might have set
|
|
for ( int i = 0 ; i < QColorDialog::customCount() ; i++ )
|
|
settings.setValue("CustomColor/" + QString::number(i),QColorDialog::customColor(i));
|
|
}
|
|
else
|
|
{
|
|
getTreeWidget()->resetPropertyCallback();
|
|
if (FFlag::FixColorSettingsCancel && !getTreeWidget()->hasOriginalValues())
|
|
{
|
|
setVariantValue(originalColor);
|
|
commitModification();
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
else
|
|
{
|
|
getTreeWidget()->restoreOriginalValues(this);
|
|
getTreeWidget()->resetOriginalValues();
|
|
}
|
|
}
|
|
|
|
m_pPopupLaunchEditor = NULL; m_pProxyLineEdit = NULL;
|
|
}
|
|
|
|
void ColorPropertyItem::updatePropertyValue(QColor selectedColor)
|
|
{
|
|
G3D::Color3 color = G3D::Color3::fromARGB(selectedColor.rgba());
|
|
setVariantValue(color);
|
|
|
|
commitModification(false);
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
|
|
void ColorPropertyItem::setModelDataSafe(QWidget *editor)
|
|
{
|
|
if (m_pPopupLaunchEditor && m_pProxyLineEdit && (m_pProxyLineEdit->text() != text(1)))
|
|
{
|
|
G3D::Color3 editedColor;
|
|
if (RBX::StringConverter<G3D::Color3>::convertToValue(m_pProxyLineEdit->text().toStdString(), editedColor))
|
|
{
|
|
setVariantValue(G3D::Color3(editedColor.r/255.0f, editedColor.g/255.0f, editedColor.b/255.0f));
|
|
commitModification();
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ColorPropertyItem::setModelData(QWidget *editor)
|
|
{
|
|
if (m_pPopupLaunchEditor && m_pProxyLineEdit && (m_pProxyLineEdit->text() != text(1)))
|
|
{
|
|
G3D::Color3 editedColor;
|
|
if (RBX::StringConverter<G3D::Color3>::convertToValue(m_pProxyLineEdit->text().toStdString(), editedColor))
|
|
{
|
|
setVariantValue(G3D::Color3(editedColor.r/255.0f, editedColor.g/255.0f, editedColor.b/255.0f));
|
|
commitModification();
|
|
|
|
m_isMultiValued = false;
|
|
updateIcon();
|
|
}
|
|
|
|
m_pPopupLaunchEditor = NULL; m_pProxyLineEdit = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
int ColorPropertyItem::popupLauncherButtonSize()
|
|
{
|
|
return PROP_BUTTON_SIZE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// FontPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class FontPropertyItem: public PropertyItem
|
|
{
|
|
public:
|
|
|
|
FontPropertyItem(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
QFont font = m_variantValue.get<QFont>();
|
|
QString text = font.family() + " : " + QString::number(font.pointSize()) + "pt";
|
|
|
|
if ( font.bold() )
|
|
text += ", Bold";
|
|
if ( font.underline() )
|
|
text += ", Underline";
|
|
if ( font.italic() )
|
|
text += ", Italic";
|
|
if ( font.strikeOut() )
|
|
text += ", Strikeout";
|
|
|
|
if ( !font.bold() && !font.underline() && !font.italic() && !font.strikeOut() )
|
|
text += ", Normal";
|
|
|
|
return text;
|
|
}
|
|
|
|
bool editorEvent(QEvent* event)
|
|
{
|
|
if ( !m_pPropertyDescriptor->isReadOnly() && (event->type() == QEvent::MouseButtonRelease) )
|
|
{
|
|
QFont originalFont = m_variantValue.get<QFont>();
|
|
bool ok = false;
|
|
QFont newFont = QFontDialog::getFont(
|
|
&ok,
|
|
originalFont,
|
|
getTreeWidget(),
|
|
m_pPropertyDescriptor->name.c_str() );
|
|
|
|
if ( ok && originalFont != newFont )
|
|
{
|
|
setVariantValue(newFont);
|
|
commitModification();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// DirPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class DirPropertyItem: public PropertyItem
|
|
{
|
|
public:
|
|
|
|
DirPropertyItem(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
QDir dir = m_variantValue.get<QDir>();
|
|
return dir.absolutePath();
|
|
}
|
|
|
|
bool editorEvent(QEvent* event)
|
|
{
|
|
if ( !m_pPropertyDescriptor->isReadOnly() && (event->type() == QEvent::MouseButtonRelease) )
|
|
{
|
|
QString originalDir = m_variantValue.get<QDir>().absolutePath();
|
|
|
|
QString newDir;
|
|
|
|
newDir = QFileDialog::getExistingDirectory(getTreeWidget(),"Path",originalDir);
|
|
|
|
if ( !newDir.isEmpty() )
|
|
{
|
|
setVariantValue(QDir(newDir));
|
|
commitModification();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// RefPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class RefPropertyItem: public PropertyItem
|
|
{
|
|
QString m_TextValue;
|
|
public:
|
|
RefPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
//read only
|
|
setFlags(Qt::NoItemFlags);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
std::string val = m_variantValue.get<std::string>();
|
|
return val.c_str();
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
const RBX::Reflection::RefPropertyDescriptor* pRefProp = dynamic_cast<const RBX::Reflection::RefPropertyDescriptor*>(m_pPropertyDescriptor);
|
|
const RBX::Instance *pParentInstance = boost::polymorphic_downcast<const RBX::Instance*>(pRefProp->getRefValue(pInstance));
|
|
setVariantValue(pParentInstance ? pParentInstance->getName() : std::string(""));
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance*)
|
|
{
|
|
//no value change!!!
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// PrimaryPartPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class PrimaryPartPropertyItem: public PropertyItem
|
|
{
|
|
QString m_TextValue;
|
|
boost::shared_ptr<RBX::ModelInstance> m_pModelInstance;
|
|
QPointer<PrimaryPartSelectionEditor> m_pPrimaryPartSelEditor;
|
|
|
|
public:
|
|
PrimaryPartPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_pPrimaryPartSelEditor(NULL)
|
|
{
|
|
setFlags(Qt::NoItemFlags);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
std::string val = m_variantValue.get<std::string>();
|
|
return QString::fromStdString(val);
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
// make sure we enable edit if the no. of selected parts are only 1
|
|
RBX::Selection* selection = RBX::ServiceProvider::find<RBX::Selection>(pInstance);
|
|
if (!selection || selection->size() != 1)
|
|
{
|
|
setVariantValue(std::string(""));
|
|
setFlags(Qt::NoItemFlags);
|
|
m_pModelInstance.reset();
|
|
return;
|
|
}
|
|
|
|
m_pModelInstance = shared_from(RBX::Instance::fastDynamicCast<RBX::ModelInstance>(pInstance));
|
|
if (!m_pModelInstance)
|
|
throw std::runtime_error("Invalid object");
|
|
|
|
setFlags(Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsEnabled);
|
|
|
|
std::string strVal;
|
|
RBX::PartInstance* pPartInstance = m_pModelInstance->getPrimaryPartSetByUser();
|
|
if (pPartInstance)
|
|
strVal = pPartInstance->getName().c_str();
|
|
|
|
setVariantValue(strVal);
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance* pInstance)
|
|
{
|
|
if (!pInstance || !m_pPropertyDescriptor)
|
|
return;
|
|
|
|
std::string strVal;
|
|
RBX::ModelInstance* mInstance = RBX::Instance::fastDynamicCast<RBX::ModelInstance>(pInstance);
|
|
if (mInstance)
|
|
{
|
|
RBX::PartInstance* pPartInstance = mInstance->getPrimaryPartSetByUser();
|
|
if (pPartInstance)
|
|
strVal = pPartInstance->getName().c_str();
|
|
}
|
|
|
|
setVariantValue(strVal);
|
|
m_pModelInstance.reset();
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QString partName(text(1));
|
|
if (partName.isEmpty())
|
|
partName = "No primary part";
|
|
|
|
if (!m_pPrimaryPartSelEditor.isNull())
|
|
delete m_pPrimaryPartSelEditor;
|
|
|
|
m_pPrimaryPartSelEditor = new PrimaryPartSelectionEditor(parent, this, partName, m_pModelInstance);
|
|
m_pPrimaryPartSelEditor->setGeometry(option.rect);
|
|
m_pPrimaryPartSelEditor->setAutoFillBackground(true);
|
|
|
|
UpdateUIManager::Instance().updateToolBars();
|
|
|
|
return m_pPrimaryPartSelEditor;
|
|
}
|
|
|
|
void buttonClicked(const QString& buttonName)
|
|
{
|
|
if (buttonName == "removeButton")
|
|
{
|
|
// remove primary part
|
|
if (m_pModelInstance)
|
|
m_pModelInstance->setPrimaryPartSetByUser(NULL);
|
|
setVariantValue(std::string(""));
|
|
// close editor
|
|
if (!m_pPrimaryPartSelEditor.isNull())
|
|
getTreeWidget()->closeEditor(m_pPrimaryPartSelEditor, QAbstractItemDelegate::NoHint);
|
|
}
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
if (!m_pModelInstance)
|
|
return;
|
|
|
|
if (!editor)
|
|
{
|
|
std::string strVal;
|
|
RBX::PartInstance* pPartInstance = m_pModelInstance->getPrimaryPartSetByUser();
|
|
if (pPartInstance)
|
|
strVal = pPartInstance->getName().c_str();
|
|
setVariantValue(strVal);
|
|
commitModification();
|
|
}
|
|
|
|
if (!m_pPrimaryPartSelEditor.isNull())
|
|
getTreeWidget()->closeEditor(m_pPrimaryPartSelEditor, QAbstractItemDelegate::NoHint);
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// PhysicalPropertiesItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class PhysicalPropertiesItem: public PropertyItem
|
|
{
|
|
DoublePropertyItem *m_pChild[5];
|
|
bool m_checkToggled;
|
|
int m_componentToUpdate;
|
|
int m_isChecked;
|
|
|
|
enum PhysicalPropertiesVar
|
|
{
|
|
PhysProp_Density = 0,
|
|
PhysProp_Friction = 1,
|
|
PhysProp_Elasticity = 2,
|
|
PhysProp_FrictionWeight = 3,
|
|
PhysProp_ElasticityWeight = 4
|
|
};
|
|
|
|
public:
|
|
PhysicalPropertiesItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_componentToUpdate(-1)
|
|
, m_checkToggled(false)
|
|
, m_isChecked(0)
|
|
{
|
|
setIcon(1, getCheckBox(m_isChecked, false));
|
|
|
|
m_pChild[PhysProp_Density] = new DoublePropertyItem(this, "Density");
|
|
addChild(m_pChild[PhysProp_Density]);
|
|
|
|
m_pChild[PhysProp_Friction] = new DoublePropertyItem(this, "Friction");
|
|
addChild(m_pChild[PhysProp_Friction]);
|
|
|
|
m_pChild[PhysProp_Elasticity] = new DoublePropertyItem(this, "Elasticity");
|
|
addChild(m_pChild[PhysProp_Elasticity]);
|
|
|
|
m_pChild[PhysProp_FrictionWeight] = new DoublePropertyItem(this, "FrictionWeight");
|
|
addChild(m_pChild[PhysProp_FrictionWeight]);
|
|
|
|
m_pChild[PhysProp_ElasticityWeight] = new DoublePropertyItem(this, "ElasticityWeight");
|
|
addChild(m_pChild[PhysProp_ElasticityWeight]);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = 0;
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>*)(m_pPropertyDescriptor);
|
|
if (pTypedDesc)
|
|
{
|
|
RBX::PhysicalProperties value1 = pTypedDesc->getValue(pPreviousInstance);
|
|
RBX::PhysicalProperties value2 = pTypedDesc->getValue(pCurrentInstance);
|
|
|
|
result = value1 == value2;
|
|
|
|
if (value1.getCustomEnabled() != value2.getCustomEnabled())
|
|
{
|
|
setIcon(1, getCheckBox(-1, false));
|
|
result = -1;
|
|
}
|
|
if (value1.getDensity() != value2.getDensity())
|
|
{
|
|
m_pChild[PhysProp_Density]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
if (value1.getFriction() != value2.getFriction())
|
|
{
|
|
m_pChild[PhysProp_Friction]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
if (value1.getElasticity() != value2.getElasticity())
|
|
{
|
|
m_pChild[PhysProp_Elasticity]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
if (value1.getFrictionWeight() != value2.getFrictionWeight())
|
|
{
|
|
m_pChild[PhysProp_FrictionWeight]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
if (value1.getElasticityWeight() != value2.getElasticityWeight())
|
|
{
|
|
m_pChild[PhysProp_ElasticityWeight]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
RBX::PhysicalProperties modifiedProperties;
|
|
if (m_isChecked == 1)
|
|
{
|
|
modifiedProperties = RBX::PhysicalProperties(
|
|
(float) m_pChild[PhysProp_Density]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_Friction]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_Elasticity]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_FrictionWeight]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_ElasticityWeight]->getVariantValue().get<double>());
|
|
}
|
|
else
|
|
{
|
|
modifiedProperties = RBX::PhysicalProperties();
|
|
}
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
setVariantValue(modifiedProperties);
|
|
commitModification();
|
|
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = PhysProp_Density;
|
|
if (m_pChild[PhysProp_Friction] == pChildItem)
|
|
m_componentToUpdate = PhysProp_Friction;
|
|
else if (m_pChild[PhysProp_Elasticity] == pChildItem)
|
|
m_componentToUpdate = PhysProp_Elasticity;
|
|
else if (m_pChild[PhysProp_FrictionWeight] == pChildItem)
|
|
m_componentToUpdate = PhysProp_FrictionWeight;
|
|
else if (m_pChild[PhysProp_ElasticityWeight] == pChildItem)
|
|
m_componentToUpdate = PhysProp_ElasticityWeight;
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0 && !m_checkToggled)
|
|
{
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>*)(m_pPropertyDescriptor);
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
//set only the modified component
|
|
RBX::PhysicalProperties value = pTypedDesc->getValue(pInstance);
|
|
float currentDensity = value.getDensity();
|
|
float currentFriction = value.getFriction();
|
|
float currentElasticity = value.getElasticity();
|
|
float currentFrictionWeight = value.getFrictionWeight();
|
|
float currentElasticityWeight = value.getElasticityWeight();
|
|
if (m_checkToggled)
|
|
{
|
|
if (m_isChecked && !value.getCustomEnabled())
|
|
{
|
|
RBX::PartInstance* ourPart = RBX::Instance::fastDynamicCast<RBX::PartInstance>(pInstance);
|
|
RBX::PhysicalProperties materialProp = RBX::MaterialProperties::generatePhysicalMaterialFromPartMaterial(ourPart->getRenderMaterial());
|
|
value = materialProp;
|
|
}
|
|
else if (!m_isChecked && value.getCustomEnabled())
|
|
{
|
|
value = RBX::PhysicalProperties();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value = RBX::PhysicalProperties(
|
|
(float) m_pChild[PhysProp_Density]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_Friction]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_Elasticity]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_FrictionWeight]->getVariantValue().get<double>(),
|
|
(float) m_pChild[PhysProp_ElasticityWeight]->getVariantValue().get<double>());
|
|
}
|
|
/*
|
|
else if (m_componentToUpdate == PhysProp_Density)
|
|
{
|
|
value = RBX::PhysicalProperties(m_pChild[PhysProp_Density]->getVariantValue().get<double>(), currentFriction, currentElasticity, currentFrictionWeight, currentElasticityWeight);
|
|
}
|
|
else if (m_componentToUpdate == PhysProp_Friction)
|
|
{
|
|
value = RBX::PhysicalProperties(currentDensity, m_pChild[PhysProp_Friction]->getVariantValue().get<double>(), currentElasticity, currentFrictionWeight, currentElasticityWeight);
|
|
}
|
|
else if (m_componentToUpdate == PhysProp_Elasticity)
|
|
{
|
|
value = RBX::PhysicalProperties(currentDensity, currentFriction, m_pChild[PhysProp_Elasticity]->getVariantValue().get<double>(), currentFrictionWeight, currentElasticityWeight);
|
|
}
|
|
else if (m_componentToUpdate == PhysProp_FrictionWeight)
|
|
{
|
|
value = RBX::PhysicalProperties(currentDensity, currentFriction, currentElasticity, m_pChild[PhysProp_FrictionWeight]->getVariantValue().get<double>(), currentElasticityWeight);
|
|
}
|
|
else if (m_componentToUpdate == PhysProp_ElasticityWeight)
|
|
{
|
|
value = RBX::PhysicalProperties(currentDensity, currentFriction, currentElasticity, currentFrictionWeight, m_pChild[PhysProp_ElasticityWeight]->getVariantValue().get<double>());
|
|
}*/
|
|
|
|
m_variantValue = RBX::Reflection::Variant(value);
|
|
pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
RBX::PhysicalProperties propertyVal = m_variantValue.get<RBX::PhysicalProperties>();
|
|
m_isChecked = propertyVal.getCustomEnabled();
|
|
setIcon(1, getCheckBox(m_isChecked, false));
|
|
m_pChild[PhysProp_Density]->setVariantValue(propertyVal.getDensity());
|
|
m_pChild[PhysProp_Friction]->setVariantValue(propertyVal.getFriction());
|
|
m_pChild[PhysProp_Elasticity]->setVariantValue(propertyVal.getElasticity());
|
|
m_pChild[PhysProp_FrictionWeight]->setVariantValue(propertyVal.getFrictionWeight());
|
|
m_pChild[PhysProp_ElasticityWeight]->setVariantValue(propertyVal.getElasticityWeight());
|
|
|
|
for (size_t i = 0; i < 5; i ++)
|
|
{
|
|
m_pChild[i]->setHidden(!m_isChecked);
|
|
}
|
|
}
|
|
|
|
QString getTextValue()
|
|
{ return QString("");}
|
|
|
|
void toggleState()
|
|
{
|
|
m_isChecked = !m_isChecked;
|
|
setIcon(1, getCheckBox(m_isChecked, false));
|
|
m_checkToggled = true;
|
|
commitModification();
|
|
m_checkToggled = false;
|
|
}
|
|
|
|
bool editorEvent(QEvent * pEvent)
|
|
{
|
|
if (!m_pPropertyDescriptor->isReadOnly() && (pEvent->type() == QEvent::MouseButtonRelease))
|
|
{
|
|
QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);
|
|
if (pMouseEvent && (pMouseEvent->button() & Qt::LeftButton))
|
|
{
|
|
toggleState();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual void setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
m_variantValue = value;
|
|
|
|
if (FFlag::StudioPropertyErrorOutput)
|
|
{
|
|
updateChildren();
|
|
RBX::PhysicalProperties currentProperty = m_variantValue.get<RBX::PhysicalProperties>();
|
|
RBX::PhysicalProperties vectorVal;
|
|
if (currentProperty.getCustomEnabled())
|
|
{
|
|
vectorVal = RBX::PhysicalProperties(
|
|
m_pChild[PhysProp_Density]->getVariantValue().get<double>()
|
|
, m_pChild[PhysProp_Friction]->getVariantValue().get<double>()
|
|
, m_pChild[PhysProp_Elasticity]->getVariantValue().get<double>()
|
|
, m_pChild[PhysProp_FrictionWeight]->getVariantValue().get<double>()
|
|
, m_pChild[PhysProp_ElasticityWeight]->getVariantValue().get<double>());
|
|
}
|
|
else
|
|
{
|
|
vectorVal = RBX::PhysicalProperties();
|
|
}
|
|
|
|
m_variantValue = vectorVal;
|
|
}
|
|
|
|
//also set its text value
|
|
setTextValue(getTextValue());
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// VectorPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class VectorPropertyItem: public PropertyItem
|
|
{
|
|
DoublePropertyItem *m_pChild[3];
|
|
int m_componentToUpdate;
|
|
public:
|
|
VectorPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_componentToUpdate(-1)
|
|
{
|
|
m_pChild[0] = new DoublePropertyItem(this, "X");
|
|
addChild(m_pChild[0]);
|
|
|
|
m_pChild[1] = new DoublePropertyItem(this, "Y");
|
|
addChild(m_pChild[1]);
|
|
|
|
m_pChild[2] = new DoublePropertyItem(this, "Z");
|
|
addChild(m_pChild[2]);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = 0;
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>*)(m_pPropertyDescriptor);
|
|
if (pTypedDesc)
|
|
{
|
|
G3D::Vector3 value1 = pTypedDesc->getValue(pPreviousInstance);
|
|
G3D::Vector3 value2 = pTypedDesc->getValue(pCurrentInstance);
|
|
result = value1 == value2;
|
|
|
|
//set appropriate values in children
|
|
|
|
for (int ii=0; ii<3; ++ii)
|
|
{
|
|
if (value1[ii] != value2[ii])
|
|
{
|
|
m_pChild[ii]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
G3D::Vector3 modifiedValue;
|
|
for (int ii=0; ii<3; ++ii)
|
|
modifiedValue[ii] = m_pChild[ii]->getVariantValue().get<double>();
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = 0;
|
|
if (m_pChild[1] == pChildItem)
|
|
m_componentToUpdate = 1;
|
|
else if (m_pChild[2] == pChildItem)
|
|
m_componentToUpdate = 2;
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info
|
|
setText(1, "");
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0)
|
|
{
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>*)(m_pPropertyDescriptor);
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
//set only the modified component
|
|
G3D::Vector3 value = pTypedDesc->getValue(pInstance);
|
|
value[m_componentToUpdate] = m_pChild[m_componentToUpdate]->getVariantValue().get<double>();
|
|
|
|
m_variantValue = RBX::Reflection::Variant(value);
|
|
|
|
if (!handleCollisionLocally(pInstance))
|
|
pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
G3D::Vector3 vectorVal = m_variantValue.get<G3D::Vector3>();
|
|
return QString("%1, %2, %3").arg(format(vectorVal.x)).arg(format(vectorVal.y)).arg(format(vectorVal.z));
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
G3D::Vector3 vectorVal;
|
|
if (RBX::StringConverter<G3D::Vector3>::convertToValue(pLineEdit->text().toStdString(), vectorVal))
|
|
{
|
|
setVariantValue(vectorVal);
|
|
commitModification();
|
|
|
|
if (!FFlag::StudioPropertyErrorOutput)
|
|
updateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
m_variantValue = value;
|
|
|
|
if (FFlag::StudioPropertyErrorOutput)
|
|
{
|
|
updateChildren();
|
|
|
|
G3D::Vector3 vectorVal = G3D::Vector3(
|
|
m_pChild[0]->getVariantValue().get<double>()
|
|
, m_pChild[1]->getVariantValue().get<double>()
|
|
, m_pChild[2]->getVariantValue().get<double>());
|
|
|
|
m_variantValue = vectorVal;
|
|
}
|
|
|
|
//also set its text value
|
|
setTextValue(getTextValue());
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
G3D::Vector3 vectorVal = m_variantValue.get<G3D::Vector3>();
|
|
for (int ii=0; ii<3; ++ii)
|
|
m_pChild[ii]->setVariantValue(vectorVal[ii]);
|
|
}
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// RectPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class RectPropertyItem: public PropertyItem
|
|
{
|
|
DoublePropertyItem *m_pChild[4];
|
|
int m_componentToUpdate;
|
|
public:
|
|
RectPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_componentToUpdate(-1)
|
|
{
|
|
m_pChild[0] = new DoublePropertyItem(this, "X0");
|
|
addChild(m_pChild[0]);
|
|
|
|
m_pChild[1] = new DoublePropertyItem(this, "Y0");
|
|
addChild(m_pChild[1]);
|
|
|
|
m_pChild[2] = new DoublePropertyItem(this, "X1");
|
|
addChild(m_pChild[2]);
|
|
|
|
m_pChild[3] = new DoublePropertyItem(this, "Y1");
|
|
addChild(m_pChild[3]);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = 0;
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<G3D::Rect2D>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<G3D::Rect2D>*)(m_pPropertyDescriptor);
|
|
if (pTypedDesc)
|
|
{
|
|
G3D::Rect2D value1 = pTypedDesc->getValue(pPreviousInstance);
|
|
G3D::Rect2D value2 = pTypedDesc->getValue(pCurrentInstance);
|
|
result = value1 == value2;
|
|
|
|
if (value1.x0() != value2.x0())
|
|
{
|
|
m_pChild[0]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
|
|
if (value1.y0() != value2.y0())
|
|
{
|
|
m_pChild[1]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
|
|
if (value1.x1() != value2.x1())
|
|
{
|
|
m_pChild[2]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
|
|
if (value1.y1() != value2.y1())
|
|
{
|
|
m_pChild[3]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
G3D::Rect2D modifiedValue;
|
|
modifiedValue = modifiedValue.xyxy(m_pChild[0]->getVariantValue().get<double>(),
|
|
m_pChild[1]->getVariantValue().get<double>(),
|
|
m_pChild[2]->getVariantValue().get<double>(),
|
|
m_pChild[3]->getVariantValue().get<double>());
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = 0;
|
|
if (m_pChild[1] == pChildItem)
|
|
m_componentToUpdate = 1;
|
|
else if (m_pChild[2] == pChildItem)
|
|
m_componentToUpdate = 2;
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info
|
|
setText(1, "");
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0)
|
|
{
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<G3D::Rect2D>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<G3D::Rect2D>*)(m_pPropertyDescriptor);
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
// TODO: remove because this is WILL CAUSE MEMORY LEAK
|
|
//*pTypedDesc = *((RBX::Reflection::TypedPropertyDescriptor<G3D::Rect2D>*) new G3D::Rect2D());
|
|
|
|
|
|
|
|
//if (FFlag::StudioPropertiesRespectCollisionToggle)
|
|
// m_variantValue = RBX::Reflection::Variant(value);
|
|
|
|
//if (!handleCollisionLocally(pInstance))
|
|
// pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
G3D::Rect2D vectorVal = m_variantValue.get<G3D::Rect2D>();
|
|
return QString("%1, %2, %3, %4").arg(format(vectorVal.x0())).arg(format(vectorVal.y0())).arg(format(vectorVal.x1())).arg(format(vectorVal.y1()));
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
G3D::Rect2D rectVal;
|
|
if (RBX::StringConverter<G3D::Rect2D>::convertToValue(pLineEdit->text().toStdString(), rectVal))
|
|
{
|
|
setVariantValue(rectVal);
|
|
commitModification();
|
|
|
|
updateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
G3D::Rect2D vectorVal = m_variantValue.get<G3D::Rect2D>();
|
|
m_pChild[0]->setVariantValue(vectorVal.x0());
|
|
m_pChild[1]->setVariantValue(vectorVal.y0());
|
|
m_pChild[2]->setVariantValue(vectorVal.x1());
|
|
m_pChild[3]->setVariantValue(vectorVal.y1());
|
|
}
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// UDimComponentItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class UDim2ComponentItem: public PropertyItem
|
|
{
|
|
DoublePropertyItem *m_pScale;
|
|
IntPropertyItem *m_pOffset;
|
|
int m_pComponentID;
|
|
int m_componentToUpdate;
|
|
public:
|
|
UDim2ComponentItem(PropertyItem *pParentItem, const QString &name, int componentID)
|
|
: PropertyItem(pParentItem, name)
|
|
, m_pComponentID(componentID)
|
|
{
|
|
m_pScale = new DoublePropertyItem(this, "Scale");
|
|
addChild(m_pScale);
|
|
|
|
m_pOffset = new IntPropertyItem(this, "Offset");
|
|
addChild(m_pOffset);
|
|
}
|
|
|
|
int compareInstanceValues(const RBX::UDim &previousVal, const RBX::UDim ¤tVal)
|
|
{
|
|
int result = 1;
|
|
|
|
if (previousVal.scale != currentVal.scale)
|
|
{
|
|
m_pScale->setText(1, "");
|
|
result = -1;
|
|
}
|
|
|
|
if (previousVal.offset != currentVal.offset)
|
|
{
|
|
m_pOffset->setText(1, "");
|
|
result = -1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
PropertyItem::setVariantValue(value);
|
|
updateChildren();
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
RBX::UDim uDim = m_variantValue.get<RBX::UDim>();
|
|
return QString("%1, %2").arg(format(uDim.scale)).arg(uDim.offset);
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
RBX::UDim modifiedValue;
|
|
modifiedValue.scale = m_pScale->getVariantValue().get<double>();
|
|
modifiedValue.offset = m_pOffset->getVariantValue().get<int>();
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = 0;
|
|
if (m_pOffset == pChildItem)
|
|
m_componentToUpdate = 1;
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info
|
|
setText(1, "");
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>*)(m_pParentItem->propertyDescriptor());
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
//set only the modified component
|
|
RBX::UDim2 value = pTypedDesc->getValue(pInstance);
|
|
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0)
|
|
{
|
|
value[m_pComponentID] = m_variantValue.get<RBX::UDim>();
|
|
}
|
|
else
|
|
{
|
|
if (m_componentToUpdate > 0)
|
|
value[m_pComponentID].offset = m_pOffset->getVariantValue().get<int>();
|
|
else
|
|
value[m_pComponentID].scale = m_pScale->getVariantValue().get<double>();
|
|
}
|
|
|
|
pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
RBX::UDim udimVal;
|
|
if (RBX::StringConverter<RBX::UDim>::convertToValue(pLineEdit->text().toStdString(), udimVal))
|
|
{
|
|
setVariantValue(udimVal);
|
|
commitModification();
|
|
|
|
updateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
RBX::UDim udimVal = m_variantValue.get<RBX::UDim>();
|
|
m_pScale->setVariantValue((double)udimVal.scale);
|
|
m_pOffset->setVariantValue((int)udimVal.offset);
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// UDim2PropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class UDim2PropertyItem: public PropertyItem
|
|
{
|
|
UDim2ComponentItem *m_pChild[2];
|
|
int m_componentToUpdate;
|
|
public:
|
|
UDim2PropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_componentToUpdate(-1)
|
|
{
|
|
m_pChild[0] = new UDim2ComponentItem(this, "X", 0);
|
|
addChild(m_pChild[0]);
|
|
|
|
m_pChild[1] = new UDim2ComponentItem(this, "Y", 1);
|
|
addChild(m_pChild[1]);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = 0;
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>*)(m_pPropertyDescriptor);
|
|
if (pTypedDesc)
|
|
{
|
|
RBX::UDim2 value1 = pTypedDesc->getValue(pPreviousInstance);
|
|
RBX::UDim2 value2 = pTypedDesc->getValue(pCurrentInstance);
|
|
result = value1 == value2;
|
|
|
|
//set appropriate values in children
|
|
for (int ii=0; ii < 2; ++ii)
|
|
{
|
|
if (m_pChild[ii]->compareInstanceValues(value1[ii], value2[ii]) <= 0)
|
|
{
|
|
m_pChild[ii]->setText(1, "");
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
RBX::UDim2 modifiedValue;
|
|
for (int ii=0; ii<2; ++ii)
|
|
modifiedValue[ii] = m_pChild[ii]->getVariantValue().get<RBX::UDim>();
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = 0;
|
|
if (m_pChild[1] == pChildItem)
|
|
m_componentToUpdate = 1;
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info
|
|
setText(1, "");
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0)
|
|
{
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>*)(m_pPropertyDescriptor);
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
//set only the modified component
|
|
RBX::UDim2 value = pTypedDesc->getValue(pInstance);
|
|
value[m_componentToUpdate] = m_pChild[m_componentToUpdate]->getVariantValue().get<RBX::UDim>();
|
|
pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
RBX::UDim2 uDim2 = m_variantValue.get<RBX::UDim2>();
|
|
return QString("{%1, %2},{%3, %4}").arg(format(uDim2.x.scale)).arg(uDim2.x.offset).arg(format(uDim2.y.scale)).arg(uDim2.y.offset);
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
RBX::UDim2 udimVal;
|
|
if (RBX::StringConverter<RBX::UDim2>::convertToValue(pLineEdit->text().toStdString(), udimVal))
|
|
{
|
|
setVariantValue(udimVal);
|
|
commitModification();
|
|
|
|
updateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
RBX::UDim2 udimVal = m_variantValue.get<RBX::UDim2>();
|
|
for (int ii=0; ii<2; ++ii)
|
|
m_pChild[ii]->setVariantValue(udimVal[ii]);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// FaceComponentItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class FaceComponentItem: public PropertyItem
|
|
{
|
|
RBX::NormalId m_componentId;
|
|
public:
|
|
FaceComponentItem(PropertyItem *pParentItem, const QString &name, RBX::NormalId component)
|
|
: PropertyItem(pParentItem, name)
|
|
, m_componentId(component)
|
|
{
|
|
}
|
|
|
|
int compareInstanceValues(const RBX::Faces &previousFaces, const RBX::Faces ¤tFaces)
|
|
{ return previousFaces.getNormalId(m_componentId) == currentFaces.getNormalId(m_componentId); }
|
|
|
|
QString getTextValue()
|
|
{
|
|
RBX::Faces faceVal = m_variantValue.get<RBX::Faces>();
|
|
return RBX::StringConverter<bool>::convertToString(faceVal.getNormalId(m_componentId)).c_str();
|
|
}
|
|
|
|
void getValue(RBX::Faces& value)
|
|
{
|
|
RBX::Faces faceVal = m_variantValue.get<RBX::Faces>();
|
|
value.setNormalId(m_componentId, faceVal.getNormalId(m_componentId));
|
|
}
|
|
|
|
//TODO: add face item editing!
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// FacesPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class FacesPropertyItem: public PropertyItem
|
|
{
|
|
FaceComponentItem *m_pChild[6];
|
|
int m_componentToUpdate;
|
|
public:
|
|
FacesPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, m_componentToUpdate(-1)
|
|
{
|
|
//create children
|
|
m_pChild[0] = new FaceComponentItem(this, "Top", RBX::NORM_Y);
|
|
m_pChild[1] = new FaceComponentItem(this, "Bottom", RBX::NORM_Y_NEG);
|
|
m_pChild[2] = new FaceComponentItem(this, "Back", RBX::NORM_Z);
|
|
m_pChild[3] = new FaceComponentItem(this, "Front", RBX::NORM_Z_NEG);
|
|
m_pChild[4] = new FaceComponentItem(this, "Right", RBX::NORM_X);
|
|
m_pChild[5] = new FaceComponentItem(this, "Left", RBX::NORM_X_NEG);
|
|
|
|
//add children
|
|
for (int ii=0; ii<6; ++ii)
|
|
addChild(m_pChild[ii]);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
int result = 0;
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>* pFacesPropDesc = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>*>(m_pPropertyDescriptor);
|
|
if (pFacesPropDesc)
|
|
{
|
|
RBX::Faces value1 = pFacesPropDesc->getValue(pPreviousInstance);
|
|
RBX::Faces value2 = pFacesPropDesc->getValue(pCurrentInstance);
|
|
result = value1 == value2;
|
|
|
|
//set appropriate values in children
|
|
for (int ii=0; ii<6; ++ii)
|
|
{
|
|
if (!m_pChild[ii]->compareInstanceValues(value1, value2))
|
|
{
|
|
m_pChild[ii]->setTextValue("");
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
RBX::Faces modifiedValue;
|
|
for (int ii=0; ii<6; ++ii)
|
|
m_pChild[ii]->getValue(modifiedValue);
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
m_componentToUpdate = 0;
|
|
for (int ii=0; ii<6; ++ii)
|
|
{
|
|
if (m_pChild[ii] == pChildItem)
|
|
{
|
|
m_componentToUpdate = ii;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info(TODO: check if we can update parent's value?)
|
|
setText(1, "");
|
|
//reset component
|
|
m_componentToUpdate = -1;
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
if (m_componentToUpdate < 0)
|
|
{
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>* pTypedDesc = (RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>*)(m_pPropertyDescriptor);
|
|
if (!pTypedDesc)
|
|
return;
|
|
|
|
//set only the modified component
|
|
RBX::Faces value = pTypedDesc->getValue(pInstance);
|
|
m_pChild[m_componentToUpdate]->getValue(value);
|
|
pTypedDesc->setValue(pInstance, value);
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
std::string result = RBX::StringConverter<RBX::Faces>::convertToString(m_variantValue.get<RBX::Faces>());
|
|
return result.empty() ? "" : result.c_str();
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
RBX::Faces faceVal;
|
|
if (RBX::StringConverter<RBX::Faces>::convertToValue(pLineEdit->text().toStdString(), faceVal))
|
|
{
|
|
setVariantValue(faceVal);
|
|
commitModification();
|
|
|
|
updateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
for (int ii=0; ii<6; ++ii)
|
|
m_pChild[ii]->setVariantValue(m_variantValue);
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// ContentPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class ContentPropertyItem: public StringPropertyItem
|
|
{
|
|
public:
|
|
ContentPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: StringPropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
bool ok = true;
|
|
pLineEdit->text().toInt(&ok);
|
|
|
|
if (ok)
|
|
pLineEdit->setText(QString("rbxassetid://%1").arg(pLineEdit->text()));
|
|
|
|
if (RBX::ContentProvider::isUrl(pLineEdit->text().toStdString()) || pLineEdit->text().isEmpty())
|
|
{
|
|
setVariantValue(pLineEdit->text().toStdString());
|
|
commitModification();
|
|
}
|
|
else
|
|
{
|
|
QtUtilities::RBXMessageBox msgBox;
|
|
msgBox.setIcon(QMessageBox::Warning);
|
|
msgBox.setText("\"" + pLineEdit->text() + "\" is not a valid content location.\nPlease enter an asset ID or a correctly formatted asset url.");
|
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
msgBox.exec();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// ImageAssetPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
class ImageAssetPropertyItem : public ContentPropertyItem
|
|
{
|
|
public:
|
|
ImageAssetPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: ContentPropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
virtual Qt::TextElideMode getTextElideMode() const
|
|
{
|
|
return Qt::ElideLeft;
|
|
}
|
|
|
|
bool customLaunchEditorHook(QMouseEvent* event)
|
|
{
|
|
if (UpdateUIManager::Instance().getViewWidget<RobloxGameExplorer>(eDW_GAME_EXPLORER)
|
|
.getCurrentGameId() > 0)
|
|
{
|
|
QRect rect = getTreeWidget()->visualItemRect(this);
|
|
QPoint location = getTreeWidget()->mapToGlobal(rect.bottomLeft());
|
|
boost::shared_ptr<RBX::DataModel> dm = getTreeWidget()->getDataModel();
|
|
|
|
ImagePickerWidget pickerFrame(treeWidget());
|
|
QString string = pickerFrame.getImageUrl(text(1), location, dm);
|
|
|
|
{
|
|
RBX::DataModel::LegacyLock lock(dm, RBX::DataModelJob::Write);
|
|
|
|
setVariantValue(string.toStdString());
|
|
commitModification();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// ScriptAssetPropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
class ScriptAssetPropertyItem : public PropertyItem
|
|
{
|
|
const QString kUseEmbeddedSourceText;
|
|
bool currentlyCommitting;
|
|
|
|
public:
|
|
ScriptAssetPropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
, kUseEmbeddedSourceText("[Embedded]")
|
|
, currentlyCommitting(false)
|
|
{
|
|
}
|
|
|
|
virtual Qt::TextElideMode getTextElideMode() const
|
|
{
|
|
return Qt::ElideLeft;
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
QString value = QString::fromStdString(getVariantValue().cast<RBX::ContentId>().toString());
|
|
if (value.isEmpty())
|
|
{
|
|
value = kUseEmbeddedSourceText;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QComboBox *pComboBox = new QComboBox(parent);
|
|
pComboBox->setGeometry(option.rect);
|
|
pComboBox->setFrame(UpdateUIManager::Instance().getMainWindow().isRibbonStyle());
|
|
pComboBox->setEditable(true);
|
|
|
|
pComboBox->addItem(kUseEmbeddedSourceText);
|
|
|
|
RobloxGameExplorer& rge = UpdateUIManager::Instance().getViewWidget<RobloxGameExplorer>(eDW_GAME_EXPLORER);
|
|
|
|
QString currentValue = text(1);
|
|
bool foundCurrentValue = currentValue == kUseEmbeddedSourceText;
|
|
|
|
std::vector<QString> scriptNames;
|
|
rge.getListOfScripts(&scriptNames);
|
|
for (size_t i = 0; i < scriptNames.size(); ++i)
|
|
{
|
|
RBX::ContentId contentId = RBX::ContentId::fromGameAssetName(scriptNames[i].toStdString());
|
|
QString contentIdString = QString::fromStdString(contentId.toString());
|
|
pComboBox->addItem(contentIdString);
|
|
foundCurrentValue = foundCurrentValue ||
|
|
(QString::fromStdString(contentId.toString()) == currentValue);
|
|
}
|
|
|
|
if (!foundCurrentValue)
|
|
{
|
|
pComboBox->addItem(currentValue);
|
|
}
|
|
|
|
return pComboBox;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
if (currentlyCommitting)
|
|
return;
|
|
|
|
QComboBox *pComboBox = dynamic_cast<QComboBox *>(editor);
|
|
if (!pComboBox)
|
|
return;
|
|
|
|
//set current value in the combo
|
|
int index = pComboBox->findText(text(1));
|
|
RBXASSERT(index >= 0);
|
|
pComboBox->setCurrentIndex(std::max(0, index));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QComboBox *comboBox = dynamic_cast<QComboBox *>(editor);
|
|
if (!comboBox)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
QString currentText = comboBox->currentText();
|
|
if (comboBox->currentText() != text(1))
|
|
{
|
|
if (currentText == kUseEmbeddedSourceText)
|
|
{
|
|
currentText = "";
|
|
}
|
|
RBX::ScopedAssign<bool> ignoreCommitModif(currentlyCommitting, true);
|
|
setVariantValue(RBX::ContentId(currentText.toStdString()));
|
|
commitModification();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// NumberSequencePropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class NumberSequencePropertyItem : public PropertyItem, public NumberSequencePropertyWidget::Callbacks
|
|
{
|
|
public:
|
|
NumberSequencePropertyItem(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor)
|
|
: PropertyItem(pPropertyDescriptor)
|
|
{
|
|
}
|
|
|
|
~NumberSequencePropertyItem()
|
|
{
|
|
}
|
|
|
|
|
|
QString getTextValue()
|
|
{
|
|
RBX::NumberSequence val = m_variantValue.get<RBX::NumberSequence>();
|
|
const std::vector< RBX::NumberSequenceKeypoint >& keys = val.getPoints();
|
|
if( keys.size() == 2 && keys[0].value == keys[1].value && keys[0].envelope == 0 && keys[1].envelope == 0 )
|
|
return QString("%1").arg(keys[0].value);
|
|
|
|
return "<NumberSequence>";
|
|
}
|
|
|
|
bool editorEvent(QEvent* event)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
NumberSequencePropertyWidget* w = new NumberSequencePropertyWidget(parent, this);
|
|
w->setGeometry(option.rect);
|
|
return w;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
NumberSequencePropertyWidget* w = static_cast<NumberSequencePropertyWidget*>(editor);
|
|
QString text = getTextValue();
|
|
w->textEditor->setText( (text[0] != '<' ? text : "") );
|
|
w->textEditor->setFocus();
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
NumberSequencePropertyWidget* w = static_cast<NumberSequencePropertyWidget*>(editor);
|
|
|
|
float constval;
|
|
if( 1 != sscanf( w->textEditor->text().toStdString().c_str(), "%f", &constval ) )
|
|
return;
|
|
|
|
setVariantValue( RBX::NumberSequence(constval) );
|
|
commitModification();
|
|
}
|
|
|
|
// These come from the editor widget
|
|
|
|
void onCurveClicked()
|
|
{
|
|
InstanceList selected;
|
|
getSelectedInstances(selected);
|
|
if( selected.size() != 1)
|
|
return; // no multi-edit
|
|
|
|
RBX::Instance* inst = *selected.begin();
|
|
SplineEditorAdapter* adapter = new SplineEditorAdapter(m_pPropertyDescriptor, getTreeWidget()->getDataModel(), inst);
|
|
adapter->show();
|
|
}
|
|
|
|
void onTextAccepted()
|
|
{
|
|
}
|
|
|
|
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// NumberRangePropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
class NumberRangePropertyItem : public PropertyItem
|
|
{
|
|
DoublePropertyItem* m_pMin;
|
|
DoublePropertyItem* m_pMax;
|
|
int m_componentToUpdate;
|
|
public:
|
|
NumberRangePropertyItem(const RBX::Reflection::PropertyDescriptor* pd) : PropertyItem(pd)
|
|
{
|
|
m_pMin = new DoublePropertyItem(this, "Min");
|
|
m_pMax = new DoublePropertyItem(this, "Max");
|
|
addChild(m_pMin);
|
|
addChild(m_pMax);
|
|
}
|
|
|
|
int compareInstanceValues(RBX::Instance* prev, RBX::Instance* cur)
|
|
{
|
|
int result = 0;
|
|
|
|
if (const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberRange>* propd = static_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberRange>* > ( m_pPropertyDescriptor ))
|
|
{
|
|
RBX::NumberRange a = propd->getValue(prev);
|
|
RBX::NumberRange b = propd->getValue(cur);
|
|
if (a.min != b.min)
|
|
{
|
|
m_pMin->setText(1, "");
|
|
result = -1;
|
|
}
|
|
|
|
if (a.max != b.max)
|
|
{
|
|
m_pMax->setText(1, "");
|
|
result = -1;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void setVariantValue(const RBX::Reflection::Variant& val)
|
|
{
|
|
PropertyItem::setVariantValue(val);
|
|
updateChildren();
|
|
}
|
|
|
|
QString getTextValue()
|
|
{
|
|
RBX::NumberRange r = m_variantValue.get<RBX::NumberRange>();
|
|
if(r.min == r.max)
|
|
{
|
|
return format(r.min);
|
|
}
|
|
return QString("%1, %2").arg(format(r.min), format(r.max));
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
//get modified values
|
|
float a = m_pMin->getVariantValue().get<double>();
|
|
float b = m_pMax->getVariantValue().get<double>();
|
|
RBX::NumberRange modifiedValue(std::min(a,b), std::max(a,b));
|
|
|
|
if (!m_isMultiValued)
|
|
{
|
|
//set and commit modification
|
|
setVariantValue(modifiedValue);
|
|
commitModification();
|
|
|
|
//update other children also
|
|
updateChildren();
|
|
}
|
|
else
|
|
{
|
|
//commit modifications
|
|
commitModification();
|
|
|
|
//remove parent's info
|
|
setText(1, "");
|
|
}
|
|
}
|
|
|
|
void pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
PropertyItem::pushInstanceValue(pInstance);
|
|
updateChildren();
|
|
}
|
|
|
|
void pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
//nothing special required in case there's no component modified
|
|
PropertyItem::pullInstanceValue(pInstance);
|
|
return;
|
|
}
|
|
|
|
void updateChildren()
|
|
{
|
|
//set appropriate values in children
|
|
RBX::NumberRange val = m_variantValue.get<RBX::NumberRange>();
|
|
m_pMin->setVariantValue( val.min );
|
|
m_pMax->setVariantValue( val.max );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option)
|
|
{
|
|
QLineEdit *pLineEdit = new QLineEdit(parent);
|
|
pLineEdit->setGeometry(option.rect);
|
|
pLineEdit->setFrame(false);
|
|
return pLineEdit;
|
|
}
|
|
|
|
void setEditorData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
pLineEdit->setText(text(1));
|
|
}
|
|
|
|
void setModelData(QWidget *editor)
|
|
{
|
|
QLineEdit *pLineEdit = dynamic_cast<QLineEdit *>(editor);
|
|
if (!pLineEdit)
|
|
return;
|
|
|
|
//apply values only if it has been changed
|
|
if (pLineEdit->text() != text(1))
|
|
{
|
|
std::string text = pLineEdit->text().toStdString();
|
|
float min, max;
|
|
if (2 != sscanf(text.c_str(), " %f , %f ", &min, &max))
|
|
{
|
|
if (1 != sscanf(text.c_str(), "%f", &min))
|
|
return;
|
|
|
|
max = min;
|
|
}
|
|
setVariantValue(RBX::NumberRange(min, max));
|
|
commitModification();
|
|
|
|
if (!FFlag::StudioPropertyErrorOutput)
|
|
updateChildren();
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
class ColorSequencePropertyItem : public PropertyItem
|
|
{
|
|
ColorPropertyItem* m_start;
|
|
ColorPropertyItem* m_end;
|
|
public:
|
|
|
|
ColorSequencePropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor) : PropertyItem(pPropertyDescriptor)
|
|
{
|
|
m_start = new ColorPropertyItem(this, "Start");
|
|
m_end = new ColorPropertyItem(this, "End");
|
|
addChild(m_start);
|
|
addChild(m_end);
|
|
|
|
this->setText(1, "<ColorSequence>");
|
|
}
|
|
|
|
QString getTextValue() { return "<ColorSequence>"; }
|
|
|
|
virtual void setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
m_variantValue = value;
|
|
RBX::ColorSequence cs = value.get<RBX::ColorSequence>();
|
|
|
|
m_start->setVariantValue(cs.start().value);
|
|
m_end->setVariantValue(cs.end().value);
|
|
|
|
m_start->updateIcon();
|
|
m_end->updateIcon();
|
|
this->updateIcon();
|
|
|
|
RBX::Color3 a = m_start->getVariantValue().get<RBX::Color3>();
|
|
RBX::Color3 b = m_end->getVariantValue().get<RBX::Color3>();
|
|
|
|
if (a == b)
|
|
this->setText(1, QString("[%1, %2, %3]").arg(int(a.r*255)).arg(int(a.g*255)).arg(int(a.b*255)) );
|
|
else
|
|
this->setText(1, QString("[%1, %2, %3] - [%4, %5, %6]").arg(int(a.r*255)).arg(int(a.g*255)).arg(int(a.b*255)).arg(int(b.r*255)).arg(int(b.g*255)).arg(int(b.b*255)) ); // hell yeah
|
|
}
|
|
|
|
void syncChildren(PropertyItem *pChildItem)
|
|
{
|
|
RBX::Color3 a = m_start->getVariantValue().get<RBX::Color3>();
|
|
RBX::Color3 b = m_end->getVariantValue().get<RBX::Color3>();
|
|
|
|
setVariantValue( RBX::ColorSequence(a,b) );
|
|
commitModification(true);
|
|
}
|
|
|
|
void updateIcon()
|
|
{
|
|
RBX::ColorSequence cs = getVariantValue().get<RBX::ColorSequence>();
|
|
RBX::Color3 a = cs.start().value;
|
|
RBX::Color3 b = cs.end().value;
|
|
|
|
const int H = 12;
|
|
const int W = 12;
|
|
|
|
QImage img(W, H, QImage::Format_ARGB32_Premultiplied);
|
|
img.fill(0);
|
|
|
|
QPainter painter(&img);
|
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
|
for (int x=0; x<W; ++x) // pretty lame, but this is surely temporary-ish
|
|
{
|
|
RBX::Color3 c = a.lerp(b, x/float(W-1) );
|
|
QColor qc(c.r * 255, c.g*255, c.b*255, 255);
|
|
painter.setPen(qc);
|
|
painter.drawLine(QPoint(x,0), QPoint(x,H));
|
|
}
|
|
painter.end();
|
|
|
|
this->setIcon(1, QPixmap::fromImage(img));
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
// PropertyItem
|
|
//--------------------------------------------------------------------------------------------
|
|
PropertyItem::PropertyItem(const RBX::Reflection::PropertyDescriptor *pPropertyDescriptor)
|
|
: m_pPropertyDescriptor(pPropertyDescriptor)
|
|
, m_pParentItem(NULL)
|
|
, m_isMultiValued(false)
|
|
, m_hasExceptionError(false)
|
|
{
|
|
init(m_pPropertyDescriptor->name.c_str());
|
|
|
|
//add descriptor and it's derived classes
|
|
addClassDescriptor(&m_pPropertyDescriptor->owner);
|
|
}
|
|
|
|
PropertyItem::PropertyItem(PropertyItem *pParentItem, const QString &itemName)
|
|
: m_pPropertyDescriptor(NULL)
|
|
, m_pParentItem(pParentItem)
|
|
, m_isMultiValued(false)
|
|
, m_hasExceptionError(false)
|
|
{
|
|
init(itemName);
|
|
}
|
|
|
|
PropertyItem::~PropertyItem()
|
|
{
|
|
}
|
|
|
|
void PropertyItem::init(const QString &itemName)
|
|
{
|
|
// by default items are hidden
|
|
setHidden(true);
|
|
setText(0, itemName);
|
|
setToolTip(0, itemName); // in case the name is cut off
|
|
|
|
Qt::ItemFlags flag = Qt::NoItemFlags;
|
|
if (m_pPropertyDescriptor)
|
|
{
|
|
if (!m_pPropertyDescriptor->isReadOnly())
|
|
flag = flags()|Qt::ItemIsEditable;
|
|
|
|
RBX::Reflection::Metadata::Item* metadata = RBX::Reflection::Metadata::Reflection::singleton()->get(*m_pPropertyDescriptor);
|
|
if ( metadata && !metadata->description.empty() )
|
|
setToolTip(0,QtUtilities::wrapText(QString::fromStdString(metadata->description).replace(QRegExp("<a href.*(\\/a>|\\/>)"), ""),80));
|
|
}
|
|
else if (m_pParentItem)
|
|
{
|
|
flag = m_pParentItem->flags();
|
|
}
|
|
|
|
setFlags(flag);
|
|
}
|
|
|
|
PropertyItem* PropertyItem::createItem(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor)
|
|
{
|
|
const RBX::Reflection::TypedPropertyDescriptor<bool>* pBoolProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<bool>*>(pPropertyDescriptor);
|
|
if (pBoolProp)
|
|
return new BoolPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<int>* pIntProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<int>*>(pPropertyDescriptor);
|
|
if (pIntProp)
|
|
return new IntPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<float>* pFloatProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<float>*>(pPropertyDescriptor);
|
|
if (pFloatProp)
|
|
return new DoublePropertyItem(pPropertyDescriptor);
|
|
|
|
if (const RBX::Reflection::TypedPropertyDescriptor<RBX::BrickColor>* pBrickColorProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::BrickColor>*>(pPropertyDescriptor))
|
|
if (pBrickColorProp)
|
|
return new BrickColorPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<G3D::Color3>* pColorProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<G3D::Color3>*>(pPropertyDescriptor);
|
|
if (pColorProp)
|
|
return new ColorPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::EnumPropertyDescriptor* pEnumProp = dynamic_cast<const RBX::Reflection::EnumPropertyDescriptor*>(pPropertyDescriptor);
|
|
if (pEnumProp)
|
|
return new EnumPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>* pVector3Prop = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<G3D::Vector3>*>(pPropertyDescriptor);
|
|
if (pVector3Prop)
|
|
return new VectorPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>* pPhysicalPropertiesProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::PhysicalProperties>*>(pPropertyDescriptor);
|
|
if (pPhysicalPropertiesProp)
|
|
return new PhysicalPropertiesItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::RefPropertyDescriptor* pRefProp = dynamic_cast<const RBX::Reflection::RefPropertyDescriptor*>(pPropertyDescriptor);
|
|
if (pRefProp)
|
|
{
|
|
if (strcmp(pPropertyDescriptor->name.c_str(), "PrimaryPart") == 0)
|
|
return new PrimaryPartPropertyItem(pPropertyDescriptor);
|
|
return new RefPropertyItem(pPropertyDescriptor);
|
|
}
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>* pFacesProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::Faces>*>(pPropertyDescriptor);
|
|
if (pFacesProp)
|
|
return new FacesPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>* pUdim2Prop = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::UDim2>*>(pPropertyDescriptor);
|
|
if (pUdim2Prop)
|
|
return new UDim2PropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::MeshId>* pMeshProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::MeshId>*>(pPropertyDescriptor);
|
|
if (pMeshProp)
|
|
return new ContentPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::TextureId>* pTextureProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::TextureId>*>(pPropertyDescriptor);
|
|
if (pTextureProp)
|
|
return new ImageAssetPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::Soundscape::SoundId>* pSoundProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::Soundscape::SoundId>*>(pPropertyDescriptor);
|
|
if (pSoundProp)
|
|
return new ContentPropertyItem(pPropertyDescriptor);
|
|
|
|
if (FFlag::AnimationIdIsContentPropertyItem)
|
|
{
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::AnimationId>* pAnimationProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::AnimationId>*>(pPropertyDescriptor);
|
|
if (pAnimationProp)
|
|
return new ContentPropertyItem(pPropertyDescriptor);
|
|
}
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<QFont>* pFontProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<QFont>*>(pPropertyDescriptor);
|
|
if ( pFontProp )
|
|
return new FontPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<QDir>* pDirProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<QDir>*>(pPropertyDescriptor);
|
|
if ( pDirProp )
|
|
return new DirPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberSequence>* pNSProp = dynamic_cast< const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberSequence>*>(pPropertyDescriptor);
|
|
if( pNSProp )
|
|
return new NumberSequencePropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberRange>* pNRProp = dynamic_cast< const RBX::Reflection::TypedPropertyDescriptor<RBX::NumberRange>*>(pPropertyDescriptor);
|
|
if( pNRProp )
|
|
return new NumberRangePropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::ColorSequence>* pCSProp = dynamic_cast< const RBX::Reflection::TypedPropertyDescriptor<RBX::ColorSequence>*>(pPropertyDescriptor);
|
|
if( pCSProp )
|
|
return new ColorSequencePropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::ContentId>* pContentProp = dynamic_cast<const RBX::Reflection::TypedPropertyDescriptor<RBX::ContentId>*>(pPropertyDescriptor);
|
|
if (pContentProp)
|
|
return new ScriptAssetPropertyItem(pPropertyDescriptor);
|
|
|
|
const RBX::Reflection::TypedPropertyDescriptor<RBX::Rect2D>* pRectProp = dynamic_cast< const RBX::Reflection::TypedPropertyDescriptor<RBX::Rect2D>*>(pPropertyDescriptor);
|
|
if( pRectProp )
|
|
return new RectPropertyItem(pPropertyDescriptor);
|
|
|
|
if (pPropertyDescriptor->hasStringValue())
|
|
return new StringPropertyItem(pPropertyDescriptor);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool materialPropertiesIsEnabled(const InstanceList &instances)
|
|
{
|
|
for (InstanceList::const_iterator curIter = instances.begin(); curIter != instances.end(); curIter ++)
|
|
{
|
|
if (RBX::PartInstance* part = (*curIter)->fastDynamicCast<RBX::PartInstance>())
|
|
{
|
|
if (RBX::Workspace* currentWorkspace = RBX::Workspace::findWorkspace(part))
|
|
{
|
|
return currentWorkspace->getUsingNewPhysicalProperties();
|
|
}
|
|
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PropertyItem::currentlyHidden(const InstanceList &instances)
|
|
{
|
|
// Use this function to hide properties Dynamically
|
|
|
|
// CSG PHYSICS QUALITY - FFlagCSGPhysicsLevelOfDetailEnabled
|
|
if (!FFlag::CSGPhysicsLevelOfDetailEnabled && (*propertyDescriptor() == RBX::PartOperation::prop_CollisionFidelity))
|
|
{
|
|
// Hide property if flag is disabled
|
|
return true;
|
|
}
|
|
|
|
// MATERIAL PROPERTIES - DFFlagMaterialPropertiesEnabled
|
|
// Property Hiding Logic
|
|
if (!DFFlag::MaterialPropertiesEnabled && (*propertyDescriptor() == RBX::Workspace::prop_physicalPropertiesMode))
|
|
{
|
|
// Hide workspace flag if main flag is disabled.
|
|
return true;
|
|
}
|
|
|
|
if (DFFlag::MaterialPropertiesEnabled && materialPropertiesIsEnabled(instances))
|
|
{
|
|
if (*propertyDescriptor() == RBX::PartInstance::prop_Friction ||
|
|
*propertyDescriptor() == RBX::PartInstance::prop_Elasticity)
|
|
{
|
|
// Hide old properties if Workspace Flag is true.
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (*propertyDescriptor() == RBX::PartInstance::prop_CustomPhysicalProperties)
|
|
{
|
|
// Hide new property if Workspace Flag is false.
|
|
return true;
|
|
}
|
|
}
|
|
// MATERIAL PROPERTIES done
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PropertyItem::update()
|
|
{
|
|
if (!m_pPropertyDescriptor)
|
|
return false;
|
|
|
|
m_isMultiValued = false;
|
|
if (m_hasExceptionError)
|
|
setToolTip(1, "");
|
|
m_hasExceptionError = false;
|
|
bool hasValue = false;
|
|
|
|
ClassDescriptorInstanceMap& selectionData = static_cast<PropertyTreeWidget*>(treeWidget())->getSelectionData();
|
|
if (!selectionData.empty())
|
|
{
|
|
Classes::const_iterator curClassIter = m_Classes.begin();
|
|
Classes::const_iterator endClassIter = m_Classes.end();
|
|
|
|
InstanceList::const_iterator previousIter;
|
|
|
|
while (curClassIter != endClassIter)
|
|
{
|
|
ClassDescriptorInstanceMap::const_iterator classDescIter = selectionData.find(*curClassIter);
|
|
if (classDescIter != selectionData.end())
|
|
{
|
|
if (currentlyHidden(classDescIter->second))
|
|
{
|
|
setHidden(true);
|
|
return true;
|
|
}
|
|
InstanceList::const_iterator curIter = classDescIter->second.begin(), endIter = classDescIter->second.end();
|
|
while (curIter != endIter)
|
|
{
|
|
if (!hasValue)
|
|
{
|
|
previousIter = curIter;
|
|
|
|
try
|
|
{
|
|
pushInstanceValue(*curIter);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
setTextValue(""); // remove any previously set value
|
|
m_hasExceptionError = true;
|
|
setToolTip(1, QString(e.what()));
|
|
}
|
|
|
|
hasValue = true;
|
|
}
|
|
else
|
|
{
|
|
int result = 0;
|
|
|
|
try
|
|
{
|
|
result = compareInstanceValues(*previousIter, *curIter);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
m_hasExceptionError = true;
|
|
setToolTip(1, QString(e.what()));
|
|
}
|
|
|
|
if (result <= 0)
|
|
{
|
|
//remove the value shown in the item
|
|
setTextValue("");
|
|
m_isMultiValued = true;
|
|
|
|
if (!result)
|
|
{
|
|
setHidden(false);
|
|
return true;
|
|
}
|
|
}
|
|
previousIter = curIter;
|
|
}
|
|
++curIter;
|
|
}//while (curIter != endIter)
|
|
}//if (classDescIter != selectionData.end())
|
|
++curClassIter;
|
|
}//while (curClassIter != endClassIter)
|
|
}
|
|
|
|
setHidden(!hasValue);
|
|
|
|
return hasValue;
|
|
}
|
|
|
|
bool PropertyItem::applyFilter(const QString &filterString)
|
|
{
|
|
bool filterStringFound = filterString.isEmpty() || text(0).contains(filterString, Qt::CaseInsensitive);
|
|
bool itemShown = filterStringFound && canBeShown();
|
|
setHidden(!itemShown);
|
|
return itemShown;
|
|
}
|
|
|
|
bool PropertyItem::canBeShown()
|
|
{
|
|
ClassDescriptorInstanceMap& selectionData = static_cast<PropertyTreeWidget*>(treeWidget())->getSelectionData();
|
|
if (selectionData.empty())
|
|
return false;
|
|
|
|
bool isDescriptorAvailable = false;
|
|
|
|
Classes::const_iterator curIter = m_Classes.begin();
|
|
Classes::const_iterator endIter = m_Classes.end();
|
|
|
|
while (curIter != endIter)
|
|
{
|
|
//if one of the supported classes exists in the selected instances then we can show this item
|
|
ClassDescriptorInstanceMap::const_iterator classDescIter = selectionData.find(*curIter);
|
|
if (classDescIter != selectionData.end())
|
|
{
|
|
isDescriptorAvailable = true;
|
|
break;
|
|
}
|
|
++curIter;
|
|
}
|
|
|
|
return isDescriptorAvailable;
|
|
}
|
|
|
|
void PropertyItem::setTextValue(const QString &value)
|
|
{ setText(1, value); }
|
|
|
|
QString PropertyItem::getTextValue()
|
|
{ return QString(""); }
|
|
|
|
int PropertyItem::compareInstanceValues(RBX::Instance *pPreviousInstance, RBX::Instance *pCurrentInstance)
|
|
{
|
|
if (!m_pPropertyDescriptor)
|
|
return 0;
|
|
|
|
return m_pPropertyDescriptor->equalValues(pPreviousInstance, pCurrentInstance);
|
|
}
|
|
|
|
void PropertyItem::pushInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
if (!pInstance || !m_pPropertyDescriptor)
|
|
return;
|
|
|
|
//set variant value
|
|
RBX::Reflection::Variant value;
|
|
m_pPropertyDescriptor->getVariant(pInstance, value);
|
|
setVariantValue(value);
|
|
}
|
|
|
|
void PropertyItem::pullInstanceValue(RBX::Instance *pInstance)
|
|
{
|
|
if (!m_pPropertyDescriptor || !pInstance)
|
|
return;
|
|
|
|
if (!handleCollisionLocally(pInstance))
|
|
m_pPropertyDescriptor->setVariant(pInstance, m_variantValue);
|
|
}
|
|
|
|
void PropertyItem::setVariantValue(const RBX::Reflection::Variant &value)
|
|
{
|
|
m_variantValue = value;
|
|
//also set its text value
|
|
setTextValue(getTextValue());
|
|
}
|
|
|
|
RBX::Reflection::Variant PropertyItem::getVariantValue()
|
|
{ return m_variantValue; }
|
|
|
|
void PropertyItem::addClassDescriptor(const RBX::Reflection::ClassDescriptor* pClassDescriptor)
|
|
{
|
|
if (!m_pPropertyDescriptor)
|
|
return;
|
|
|
|
m_Classes.push_back(pClassDescriptor);
|
|
|
|
// Recursively add each slot of derived classes
|
|
std::for_each(pClassDescriptor->derivedClasses_begin(),
|
|
pClassDescriptor->derivedClasses_end(),
|
|
boost::bind(&PropertyItem::addClassDescriptor, this, _1));
|
|
}
|
|
|
|
void PropertyItem::getSelectedInstances(InstanceList &instances)
|
|
{
|
|
ClassDescriptorInstanceMap& selectionData = static_cast<PropertyTreeWidget*>(treeWidget())->getSelectionData();
|
|
if (!selectionData.empty())
|
|
{
|
|
Classes::const_iterator curClassIter = m_Classes.begin();
|
|
Classes::const_iterator endClassIter = m_Classes.end();
|
|
|
|
while (curClassIter != endClassIter)
|
|
{
|
|
ClassDescriptorInstanceMap::const_iterator classDescIter = selectionData.find(*curClassIter);
|
|
if (classDescIter != selectionData.end())
|
|
instances.insert(instances.end(), classDescIter->second.begin(), classDescIter->second.end());
|
|
++curClassIter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PropertyItem::commitModification(bool requestWaypoint)
|
|
{
|
|
try
|
|
{
|
|
if (m_pPropertyDescriptor)
|
|
{
|
|
//get selected instances and set value appropriately
|
|
InstanceList instancesToModify;
|
|
getSelectedInstances(instancesToModify);
|
|
|
|
boost::shared_ptr<RBX::DataModel> pDataModel = getTreeWidget()->getDataModel();
|
|
if ( pDataModel.get() )
|
|
{
|
|
RBX::DataModel::LegacyLock lock(pDataModel, RBX::DataModelJob::Write);
|
|
|
|
//now modify values
|
|
for (InstanceList::iterator iter = instancesToModify.begin(); iter != instancesToModify.end(); ++iter)
|
|
pullInstanceValue(*iter);
|
|
|
|
//for undo/redo
|
|
if (requestWaypoint)
|
|
RBX::ChangeHistoryService::requestWaypoint(m_pPropertyDescriptor->name.c_str(), pDataModel.get());
|
|
|
|
pDataModel->setDirty(true);
|
|
}
|
|
else
|
|
{
|
|
//now modify values
|
|
for (InstanceList::iterator iter = instancesToModify.begin(); iter != instancesToModify.end(); ++iter)
|
|
pullInstanceValue(*iter);
|
|
}
|
|
|
|
/*
|
|
some setters clamp the value within certain bounds
|
|
if the clamped value is equal to the current value, the changed event won't fire
|
|
this is necessary to update the value in property widget
|
|
*/
|
|
for (InstanceList::iterator iter = instancesToModify.begin(); iter != instancesToModify.end(); ++iter)
|
|
pushInstanceValue(*iter);
|
|
}
|
|
|
|
if (m_pParentItem)
|
|
m_pParentItem->syncChildren(this);
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
{
|
|
RBX::StandardOut::singleton()->print(RBX::MESSAGE_ERROR, e.what());
|
|
}
|
|
}
|
|
|
|
QPoint PropertyItem::computePopupLocation(const QSize &pickerFrameSize)
|
|
{
|
|
QPoint location;
|
|
|
|
QRect rect = getTreeWidget()->visualItemRect(this);
|
|
QRect screen = QApplication::desktop()->availableGeometry(getTreeWidget());
|
|
|
|
if (getTreeWidget()->mapToGlobal(QPoint(0, rect.bottom())).y() + pickerFrameSize.height() <= screen.height())
|
|
location = getTreeWidget()->mapToGlobal(rect.bottomLeft());
|
|
else
|
|
location = getTreeWidget()->mapToGlobal(rect.topLeft() - QPoint(0, pickerFrameSize.height()));
|
|
|
|
location.rx() = qMax(screen.left(), qMin(location.x(), screen.right() - pickerFrameSize.width())) - 18;
|
|
location.ry() += 24;
|
|
|
|
return location;
|
|
}
|
|
|
|
PropertyTreeWidget* PropertyItem::getTreeWidget()
|
|
{ return static_cast<PropertyTreeWidget*>(treeWidget()); }
|
|
|
|
bool PropertyItem::handleCollisionLocally(RBX::Instance* pInstance)
|
|
{
|
|
if (!RBX::AdvArrowTool::advCollisionCheckMode &&
|
|
m_variantValue.isType<RBX::Vector3>())
|
|
{
|
|
if (RBX::PartInstance* partInstance = pInstance->fastDynamicCast<RBX::PartInstance>())
|
|
{
|
|
QString propertyName = m_pPropertyDescriptor->name.c_str();
|
|
if (propertyName == "Position")
|
|
{
|
|
RBX::Vector3 position = m_variantValue.get<RBX::Vector3>();
|
|
G3D::CoordinateFrame cFrame(partInstance->getCoordinateFrame().rotation, position);
|
|
partInstance->setCoordinateFrame(cFrame);
|
|
return true;
|
|
}
|
|
else if (propertyName == "Rotation")
|
|
{
|
|
RBX::Vector3 rotationVector = m_variantValue.get<RBX::Vector3>();
|
|
G3D::Matrix3 rotation = G3D::Matrix3::fromEulerAnglesXYZ(RBX::Math::degreesToRadians(rotationVector.x),RBX::Math::degreesToRadians(rotationVector.y),RBX::Math::degreesToRadians(rotationVector.z));
|
|
G3D::CoordinateFrame cFrame(rotation, partInstance->getCoordinateFrame().translation);
|
|
partInstance->setCoordinateFrame(cFrame);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static QIcon getCheckBox(int value, bool readOnly)
|
|
{
|
|
QPixmap pixmap;
|
|
if (!QPixmapCache::find(QString("CheckBoxState%1-%2").arg(value).arg(readOnly),&pixmap))
|
|
{
|
|
QStyleOptionButton opt;
|
|
if (value < 0)
|
|
opt.state |= QStyle::State_NoChange;
|
|
else
|
|
opt.state |= value ? QStyle::State_On : QStyle::State_Off;
|
|
opt.state |= readOnly ? QStyle::State_ReadOnly : QStyle::State_Enabled;
|
|
const QStyle *style = QApplication::style();
|
|
const int indicatorWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &opt);
|
|
const int indicatorHeight = style->pixelMetric(QStyle::PM_IndicatorHeight, &opt);
|
|
const int listViewIconSize = indicatorWidth;
|
|
const int pixmapWidth = indicatorWidth;
|
|
const int pixmapHeight = qMax(indicatorHeight, listViewIconSize);
|
|
|
|
opt.rect = QRect(0, 0, indicatorWidth, indicatorHeight);
|
|
pixmap = QPixmap(pixmapWidth, pixmapHeight);
|
|
pixmap.fill(Qt::transparent);
|
|
{
|
|
const int xoff = (pixmapWidth > indicatorWidth) ? (pixmapWidth - indicatorWidth) / 2 : 0;
|
|
const int yoff = (pixmapHeight > indicatorHeight) ? (pixmapHeight - indicatorHeight) / 2 : 0;
|
|
QPainter painter(&pixmap);
|
|
painter.translate(xoff, yoff);
|
|
style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, &painter);
|
|
}
|
|
|
|
QPixmapCache::insert(QString("CheckBoxState%1-%2").arg(value).arg(readOnly), pixmap);
|
|
}
|
|
|
|
return QIcon(pixmap);
|
|
}
|
|
|
|
static QIcon getColorIcon(const QColor &color)
|
|
{
|
|
QImage img(12, 12, QImage::Format_ARGB32_Premultiplied);
|
|
img.fill(0);
|
|
|
|
QPainter painter(&img);
|
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
|
painter.setPen(QPen(Qt::black, 1));
|
|
painter.drawRect(0, 0, img.width()-1, img.height()-1);
|
|
painter.fillRect(1, 1, img.width()-2, img.height()-2, color);
|
|
painter.end();
|
|
|
|
return QPixmap::fromImage(img);
|
|
}
|
|
|
|
void trimTrailing0s(QString& s)
|
|
{
|
|
int decimalIndex = s.indexOf(".");
|
|
if ( decimalIndex == -1 )
|
|
return;
|
|
|
|
// remove trailing zeros
|
|
while ( s.endsWith("0") )
|
|
s.chop(1);
|
|
|
|
// check if we don't have any decimal places at all
|
|
if ( s.endsWith(".") )
|
|
s.chop(1);
|
|
}
|
|
|
|
QString format(double f)
|
|
{
|
|
QString s;
|
|
s.sprintf("%.3f", f);
|
|
trimTrailing0s(s);
|
|
return s;
|
|
}
|