Add javascript variable inputs: Float, Int, Check, Color, Select
parent
cc51fdafe0
commit
af792a9bdc
|
@ -404,6 +404,9 @@ HEADERS += src/updateschecker.h
|
|||
SOURCES += src/updatescheckwidget.cpp
|
||||
HEADERS += src/updatescheckwidget.h
|
||||
|
||||
SOURCES += src/intnumberwidget.cpp
|
||||
HEADERS += src/intnumberwidget.h
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
HEADERS += src/version.h
|
||||
|
|
|
@ -3346,16 +3346,20 @@ void Document::updateScript(const QString &script)
|
|||
|
||||
void Document::updateVariable(const QString &name, const std::map<QString, QString> &value)
|
||||
{
|
||||
bool needRunScript = false;
|
||||
auto variable = m_cachedVariables.find(name);
|
||||
if (variable == m_cachedVariables.end()) {
|
||||
qDebug() << "Update a nonexist variable:" << name << "value:" << value;
|
||||
m_cachedVariables[name] = value;
|
||||
needRunScript = true;
|
||||
} else if (variable->second != value) {
|
||||
variable->second = value;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (variable->second == value)
|
||||
return;
|
||||
variable->second = value;
|
||||
m_mergedVariables[name] = value;
|
||||
emit mergedVaraiblesChanged();
|
||||
if (needRunScript)
|
||||
runScript();
|
||||
}
|
||||
|
||||
void Document::updateVariableValue(const QString &name, const QString &value)
|
||||
|
@ -3368,22 +3372,36 @@ void Document::updateVariableValue(const QString &name, const QString &value)
|
|||
auto &variableValue = variable->second["value"];
|
||||
if (variableValue == value)
|
||||
return;
|
||||
qDebug() << "Update variable:" << name << "from:" << variableValue << "to:" << value;
|
||||
variableValue = value;
|
||||
m_mergedVariables[name] = variable->second;
|
||||
runScript();
|
||||
}
|
||||
|
||||
void Document::updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables)
|
||||
bool Document::updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables)
|
||||
{
|
||||
bool updated = false;
|
||||
for (const auto &it: defaultVariables) {
|
||||
if (m_mergedVariables.find(it.first) != m_mergedVariables.end())
|
||||
auto findMergedVariable = m_mergedVariables.find(it.first);
|
||||
if (findMergedVariable != m_mergedVariables.end()) {
|
||||
bool hasChangedAttribute = false;
|
||||
for (const auto &attribute: it.second) {
|
||||
if (attribute.first == "value")
|
||||
continue;
|
||||
const auto &findMatch = findMergedVariable->second.find(attribute.first);
|
||||
if (findMatch != findMergedVariable->second.end()) {
|
||||
if (findMatch->second == attribute.second)
|
||||
continue;
|
||||
}
|
||||
hasChangedAttribute = true;
|
||||
}
|
||||
if (!hasChangedAttribute)
|
||||
continue;
|
||||
}
|
||||
updated = true;
|
||||
auto findCached = m_cachedVariables.find(it.first);
|
||||
if (findCached != m_cachedVariables.end()) {
|
||||
m_mergedVariables[it.first] = findCached->second;
|
||||
m_mergedVariables[it.first] = it.second;
|
||||
m_mergedVariables[it.first]["value"] = valueOfKeyInMapOrEmpty(findCached->second, "value");
|
||||
} else {
|
||||
m_mergedVariables[it.first] = it.second;
|
||||
m_cachedVariables[it.first] = it.second;
|
||||
|
@ -3402,6 +3420,7 @@ void Document::updateDefaultVariables(const std::map<QString, std::map<QString,
|
|||
if (updated) {
|
||||
emit mergedVaraiblesChanged();
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
void Document::runScript()
|
||||
|
@ -3420,7 +3439,9 @@ void Document::runScript()
|
|||
m_scriptRunner = new ScriptRunner();
|
||||
m_scriptRunner->moveToThread(thread);
|
||||
m_scriptRunner->setScript(new QString(m_script));
|
||||
m_scriptRunner->setVariables(new std::map<QString, std::map<QString, QString>>(m_mergedVariables));
|
||||
m_scriptRunner->setVariables(new std::map<QString, std::map<QString, QString>>(
|
||||
m_mergedVariables.empty() ? m_cachedVariables : m_mergedVariables
|
||||
));
|
||||
connect(thread, &QThread::started, m_scriptRunner, &ScriptRunner::process);
|
||||
connect(m_scriptRunner, &ScriptRunner::finished, this, &Document::scriptResultReady);
|
||||
connect(m_scriptRunner, &ScriptRunner::finished, thread, &QThread::quit);
|
||||
|
@ -3435,6 +3456,7 @@ void Document::scriptResultReady()
|
|||
std::map<QString, std::map<QString, QString>> *defaultVariables = m_scriptRunner->takeDefaultVariables();
|
||||
bool errorChanged = false;
|
||||
bool consoleLogChanged = false;
|
||||
bool mergedVariablesChanged = false;
|
||||
|
||||
const QString &scriptError = m_scriptRunner->scriptError();
|
||||
if (m_scriptError != scriptError) {
|
||||
|
@ -3455,7 +3477,7 @@ void Document::scriptResultReady()
|
|||
}
|
||||
|
||||
if (nullptr != defaultVariables) {
|
||||
updateDefaultVariables(*defaultVariables);
|
||||
mergedVariablesChanged = updateDefaultVariables(*defaultVariables);
|
||||
delete defaultVariables;
|
||||
}
|
||||
|
||||
|
@ -3470,7 +3492,7 @@ void Document::scriptResultReady()
|
|||
|
||||
qDebug() << "Script run done";
|
||||
|
||||
if (m_isScriptResultObsolete) {
|
||||
if (m_isScriptResultObsolete || mergedVariablesChanged) {
|
||||
runScript();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -658,7 +658,6 @@ public slots:
|
|||
void applyPreferenceFlatShadingChange();
|
||||
void initScript(const QString &script);
|
||||
void updateScript(const QString &script);
|
||||
void updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables);
|
||||
void runScript();
|
||||
void scriptResultReady();
|
||||
void updateVariable(const QString &name, const std::map<QString, QString> &value);
|
||||
|
@ -680,6 +679,7 @@ private:
|
|||
void removeRigResults();
|
||||
void updateLinkedPart(QUuid oldPartId, QUuid newPartId);
|
||||
//void addToolToMesh(MeshLoader *mesh);
|
||||
bool updateDefaultVariables(const std::map<QString, std::map<QString, QString>> &defaultVariables);
|
||||
private: // need initialize
|
||||
bool m_isResultMeshObsolete;
|
||||
MeshGenerator *m_meshGenerator;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include <QtWidgets>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include "theme.h"
|
||||
#include "intnumberwidget.h"
|
||||
|
||||
IntNumberWidget::IntNumberWidget(QWidget *parent, bool singleLine) :
|
||||
QWidget(parent)
|
||||
{
|
||||
m_slider = new QSlider(Qt::Horizontal, this);
|
||||
m_slider->setRange(0, 100);
|
||||
m_slider->setFixedWidth(120);
|
||||
|
||||
m_label = new QLabel(this);
|
||||
m_label->setAlignment(Qt::AlignLeft);
|
||||
|
||||
connect(m_slider, &QAbstractSlider::valueChanged, [=](int value) {
|
||||
updateValueLabel(value);
|
||||
emit valueChanged(value);
|
||||
});
|
||||
|
||||
QBoxLayout *layout = nullptr;
|
||||
if (singleLine) {
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setMargin(2);
|
||||
layout->addWidget(m_slider);
|
||||
layout->addWidget(m_label);
|
||||
} else {
|
||||
layout = new QVBoxLayout(this);
|
||||
layout->setMargin(2);
|
||||
layout->addWidget(m_label);
|
||||
layout->addWidget(m_slider);
|
||||
}
|
||||
}
|
||||
|
||||
void IntNumberWidget::updateValueLabel(int value)
|
||||
{
|
||||
QString valueString = QString::number(value);
|
||||
if (m_itemName.isEmpty())
|
||||
m_label->setText(valueString);
|
||||
else
|
||||
m_label->setText(m_itemName + ": " + valueString);
|
||||
}
|
||||
|
||||
void IntNumberWidget::setItemName(const QString &name)
|
||||
{
|
||||
m_itemName = name;
|
||||
updateValueLabel(value());
|
||||
}
|
||||
|
||||
void IntNumberWidget::setRange(int min, int max)
|
||||
{
|
||||
m_slider->setRange(min, max);
|
||||
}
|
||||
|
||||
void IntNumberWidget::increaseValue()
|
||||
{
|
||||
m_slider->triggerAction(QSlider::SliderPageStepAdd);
|
||||
}
|
||||
|
||||
void IntNumberWidget::descreaseValue()
|
||||
{
|
||||
m_slider->triggerAction(QSlider::SliderPageStepSub);
|
||||
}
|
||||
|
||||
int IntNumberWidget::value() const
|
||||
{
|
||||
return m_slider->value();
|
||||
}
|
||||
|
||||
void IntNumberWidget::setValue(int value)
|
||||
{
|
||||
m_slider->setValue(value);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef DUST3D_INT_NUMBER_WIDGET_H
|
||||
#define DUST3D_INT_NUMBER_WIDGET_H
|
||||
#include <QToolButton>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QSlider)
|
||||
|
||||
class IntNumberWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IntNumberWidget(QWidget *parent = nullptr, bool singleLine=true);
|
||||
void setRange(int min, int max);
|
||||
int value() const;
|
||||
void setItemName(const QString &name);
|
||||
|
||||
public slots:
|
||||
void increaseValue();
|
||||
void descreaseValue();
|
||||
void setValue(int value);
|
||||
|
||||
signals:
|
||||
void valueChanged(int value);
|
||||
|
||||
private:
|
||||
void updateValueLabel(int value);
|
||||
|
||||
private:
|
||||
QLabel *m_label = nullptr;
|
||||
QSlider *m_slider = nullptr;
|
||||
QString m_itemName;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2,6 +2,7 @@
|
|||
#include <QElapsedTimer>
|
||||
#include <QUuid>
|
||||
#include "scriptrunner.h"
|
||||
#include "util.h"
|
||||
|
||||
JSClassID ScriptRunner::js_partClassId = 0;
|
||||
JSClassID ScriptRunner::js_componentClassId = 0;
|
||||
|
@ -206,16 +207,82 @@ static JSValue js_createNode(JSContext *context, JSValueConst thisValue,
|
|||
return node;
|
||||
}
|
||||
|
||||
static JSValue js_createVariable(JSContext *context, JSValueConst thisValue,
|
||||
static JSValue js_createFloatInput(JSContext *context, JSValueConst thisValue,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
ScriptRunner *runner = (ScriptRunner *)JS_GetContextOpaque(context);
|
||||
if (argc < 4) {
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, defaultValue, minValue, maxValue\r\n";
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
double mergedValue = 0.0;
|
||||
|
||||
const char *name = nullptr;
|
||||
double defaultValue = 0.0;
|
||||
double minValue = 0.0;
|
||||
double maxValue = 0.0;
|
||||
|
||||
name = JS_ToCString(context, argv[0]);
|
||||
if (!name)
|
||||
goto fail;
|
||||
JS_ToFloat64(context, &defaultValue, argv[1]);
|
||||
JS_ToFloat64(context, &minValue, argv[2]);
|
||||
JS_ToFloat64(context, &maxValue, argv[3]);
|
||||
|
||||
mergedValue = runner->createFloatInput(name, defaultValue, minValue, maxValue);
|
||||
JS_FreeCString(context, name);
|
||||
|
||||
return JS_NewFloat64(context, mergedValue);
|
||||
|
||||
fail:
|
||||
JS_FreeCString(context, name);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_createIntInput(JSContext *context, JSValueConst thisValue,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
ScriptRunner *runner = (ScriptRunner *)JS_GetContextOpaque(context);
|
||||
if (argc < 4) {
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, defaultValue, minValue, maxValue\r\n";
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
int64_t mergedValue = 0.0;
|
||||
|
||||
const char *name = nullptr;
|
||||
int64_t defaultValue = 0;
|
||||
int64_t minValue = 0;
|
||||
int64_t maxValue = 0;
|
||||
|
||||
name = JS_ToCString(context, argv[0]);
|
||||
if (!name)
|
||||
goto fail;
|
||||
JS_ToInt64(context, &defaultValue, argv[1]);
|
||||
JS_ToInt64(context, &minValue, argv[2]);
|
||||
JS_ToInt64(context, &maxValue, argv[3]);
|
||||
|
||||
mergedValue = runner->createIntInput(name, defaultValue, minValue, maxValue);
|
||||
JS_FreeCString(context, name);
|
||||
|
||||
return JS_NewInt64(context, mergedValue);
|
||||
|
||||
fail:
|
||||
JS_FreeCString(context, name);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_createColorInput(JSContext *context, JSValueConst thisValue,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
ScriptRunner *runner = (ScriptRunner *)JS_GetContextOpaque(context);
|
||||
if (argc < 2) {
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, value\r\n";
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, defaultValue\r\n";
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
QString mergedValue;
|
||||
QColor mergeValue;
|
||||
|
||||
const char *name = nullptr;
|
||||
const char *defaultValue = nullptr;
|
||||
|
@ -227,11 +294,12 @@ static JSValue js_createVariable(JSContext *context, JSValueConst thisValue,
|
|||
if (!defaultValue)
|
||||
goto fail;
|
||||
|
||||
mergedValue = runner->createVariable(name, defaultValue);
|
||||
mergeValue = runner->createColorInput(name, defaultValue);
|
||||
|
||||
JS_FreeCString(context, name);
|
||||
JS_FreeCString(context, defaultValue);
|
||||
|
||||
return JS_NewFloat64(context, mergedValue.toDouble());
|
||||
return JS_NewString(context, mergeValue.name().toUtf8().constData());
|
||||
|
||||
fail:
|
||||
JS_FreeCString(context, name);
|
||||
|
@ -239,6 +307,98 @@ fail:
|
|||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_createCheckInput(JSContext *context, JSValueConst thisValue,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
ScriptRunner *runner = (ScriptRunner *)JS_GetContextOpaque(context);
|
||||
if (argc < 2) {
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, defaultValue\r\n";
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
bool mergedValue = false;
|
||||
|
||||
const char *name = nullptr;
|
||||
const char *value = nullptr;
|
||||
bool defaultValue = false;
|
||||
|
||||
name = JS_ToCString(context, argv[0]);
|
||||
if (!name)
|
||||
goto fail;
|
||||
value = JS_ToCString(context, argv[1]);
|
||||
if (!value)
|
||||
goto fail;
|
||||
|
||||
defaultValue = isTrueValueString(value);
|
||||
mergedValue = runner->createCheckInput(name, defaultValue);
|
||||
JS_FreeCString(context, name);
|
||||
JS_FreeCString(context, value);
|
||||
|
||||
return JS_NewInt64(context, mergedValue);
|
||||
|
||||
fail:
|
||||
JS_FreeCString(context, name);
|
||||
JS_FreeCString(context, value);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_createSelectInput(JSContext *context, JSValueConst thisValue,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
ScriptRunner *runner = (ScriptRunner *)JS_GetContextOpaque(context);
|
||||
if (argc < 3) {
|
||||
runner->consoleLog() += "Incomplete parameters, expect: name, defaultValue, options\r\n";
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
const char *name = nullptr;
|
||||
int32_t defaultValue = 0;
|
||||
int32_t mergedValue = 0;
|
||||
JSValue *arrayItems = nullptr;
|
||||
uint32_t arrayLength = 0;
|
||||
QStringList options;
|
||||
|
||||
name = JS_ToCString(context, argv[0]);
|
||||
if (!name)
|
||||
goto fail;
|
||||
|
||||
JS_ToInt32(context, &defaultValue, argv[1]);
|
||||
|
||||
if (true != JS_IsArray(context, argv[2])) {
|
||||
runner->consoleLog() += "Expect array as the third parameter\r\n";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!js_get_fast_array(context, argv[2], &arrayItems, &arrayLength)) {
|
||||
runner->consoleLog() += "Read third parameter as array failed\r\n";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < arrayLength; ++i) {
|
||||
const char *optionValue = JS_ToCString(context, arrayItems[i]);
|
||||
if (nullptr != optionValue) {
|
||||
options.append(optionValue);
|
||||
JS_FreeCString(context, optionValue);
|
||||
} else {
|
||||
options.append("");
|
||||
}
|
||||
}
|
||||
|
||||
mergedValue = runner->createSelectInput(name, defaultValue, options);
|
||||
if (mergedValue < 0)
|
||||
mergedValue = 0;
|
||||
else if (mergedValue >= options.size())
|
||||
mergedValue = options.size() - 1;
|
||||
|
||||
JS_FreeCString(context, name);
|
||||
|
||||
return JS_NewInt32(context, mergedValue);
|
||||
|
||||
fail:
|
||||
JS_FreeCString(context, name);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
ScriptRunner::ScriptRunner()
|
||||
{
|
||||
}
|
||||
|
@ -375,7 +535,7 @@ void ScriptRunner::run()
|
|||
JS_SetContextOpaque(context, this);
|
||||
|
||||
if (nullptr != m_script &&
|
||||
!m_script->isEmpty()) {
|
||||
!m_script->trimmed().isEmpty()) {
|
||||
auto buffer = m_script->toUtf8();
|
||||
|
||||
JSValue globalObject = JS_GetGlobalObject(context);
|
||||
|
@ -391,8 +551,20 @@ void ScriptRunner::run()
|
|||
document, "createNode",
|
||||
JS_NewCFunction(context, js_createNode, "createNode", 1));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "createVariable",
|
||||
JS_NewCFunction(context, js_createVariable, "createVariable", 2));
|
||||
document, "createFloatInput",
|
||||
JS_NewCFunction(context, js_createFloatInput, "createFloatInput", 4));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "createIntInput",
|
||||
JS_NewCFunction(context, js_createIntInput, "createIntInput", 4));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "createColorInput",
|
||||
JS_NewCFunction(context, js_createColorInput, "createColorInput", 2));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "createCheckInput",
|
||||
JS_NewCFunction(context, js_createCheckInput, "createCheckInput", 2));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "createSelectInput",
|
||||
JS_NewCFunction(context, js_createSelectInput, "createSelectInput", 3));
|
||||
JS_SetPropertyStr(context,
|
||||
document, "connect",
|
||||
JS_NewCFunction(context, js_connect, "connect", 2));
|
||||
|
@ -552,13 +724,13 @@ void ScriptRunner::generateSnapshot()
|
|||
}
|
||||
}
|
||||
|
||||
QString ScriptRunner::createVariable(const QString &name, const QString &defaultValue)
|
||||
QString ScriptRunner::createInput(const QString &name, const std::map<QString, QString> &attributes)
|
||||
{
|
||||
if (nullptr != m_defaultVariables) {
|
||||
if (m_defaultVariables->find(name) != m_defaultVariables->end()) {
|
||||
m_scriptError += "Repeated variable name found: \"" + name + "\"\r\n";
|
||||
}
|
||||
(*m_defaultVariables)[name]["value"] = defaultValue;
|
||||
(*m_defaultVariables)[name] = attributes;
|
||||
}
|
||||
if (nullptr != m_variables) {
|
||||
auto findVariable = m_variables->find(name);
|
||||
|
@ -568,7 +740,73 @@ QString ScriptRunner::createVariable(const QString &name, const QString &default
|
|||
return findValue->second;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
auto findValue = attributes.find("value");
|
||||
if (findValue != attributes.end())
|
||||
return findValue->second;
|
||||
return QString();
|
||||
}
|
||||
|
||||
float ScriptRunner::createFloatInput(const QString &name, float defaultValue, float minValue, float maxValue)
|
||||
{
|
||||
std::map<QString, QString> attributes;
|
||||
attributes["input"] = "Float";
|
||||
attributes["value"] = QString::number(defaultValue);
|
||||
attributes["defaultValue"] = attributes["value"];
|
||||
attributes["minValue"] = QString::number(minValue);
|
||||
attributes["maxValue"] = QString::number(maxValue);
|
||||
auto inputValue = createInput(name, attributes);
|
||||
return inputValue.toFloat();
|
||||
}
|
||||
|
||||
int ScriptRunner::createIntInput(const QString &name, int defaultValue, int minValue, int maxValue)
|
||||
{
|
||||
std::map<QString, QString> attributes;
|
||||
attributes["input"] = "Int";
|
||||
attributes["value"] = QString::number(defaultValue);
|
||||
attributes["defaultValue"] = attributes["value"];
|
||||
attributes["minValue"] = QString::number(minValue);
|
||||
attributes["maxValue"] = QString::number(maxValue);
|
||||
auto inputValue = createInput(name, attributes);
|
||||
return inputValue.toInt();
|
||||
}
|
||||
|
||||
QColor ScriptRunner::createColorInput(const QString &name, const QColor &defaultValue)
|
||||
{
|
||||
std::map<QString, QString> attributes;
|
||||
attributes["input"] = "Color";
|
||||
attributes["value"] = defaultValue.name();
|
||||
attributes["defaultValue"] = attributes["value"];
|
||||
auto inputValue = createInput(name, attributes);
|
||||
return QColor(inputValue);
|
||||
}
|
||||
|
||||
bool ScriptRunner::createCheckInput(const QString &name, bool checked)
|
||||
{
|
||||
std::map<QString, QString> attributes;
|
||||
attributes["input"] = "Check";
|
||||
attributes["value"] = checked ? "true" : "false";
|
||||
attributes["defaultValue"] = attributes["value"];
|
||||
auto inputValue = createInput(name, attributes);
|
||||
return isTrueValueString(inputValue);
|
||||
}
|
||||
|
||||
int ScriptRunner::createSelectInput(const QString &name, int defaultSelectedIndex, const QStringList &options)
|
||||
{
|
||||
std::map<QString, QString> attributes;
|
||||
attributes["input"] = "Select";
|
||||
attributes["value"] = QString::number(defaultSelectedIndex);
|
||||
attributes["defaultValue"] = attributes["value"];
|
||||
attributes["length"] = QString::number(options.size());
|
||||
for (int i = 0; i < options.size(); ++i) {
|
||||
attributes["option" + QString::number(i)] = options[i];
|
||||
}
|
||||
auto inputValue = createInput(name, attributes);
|
||||
int selectedIndex = inputValue.toInt();
|
||||
if (selectedIndex >= options.size()) {
|
||||
m_scriptError += QString("Selected index of select input \"%1\" is been reset to 0 because of out of range\r\n").arg(name);
|
||||
selectedIndex = 0;
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
void ScriptRunner::process()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define DUST3D_SCRIPT_RUNNER_H
|
||||
#include <QObject>
|
||||
#include <QUuid>
|
||||
#include <QColor>
|
||||
#include <QStringList>
|
||||
#include "snapshot.h"
|
||||
extern "C" {
|
||||
#include "quickjs.h"
|
||||
|
@ -63,7 +65,6 @@ public:
|
|||
std::map<QString, std::map<QString, QString>> *takeDefaultVariables();
|
||||
const QString &scriptError();
|
||||
static void mergeVaraibles(std::map<QString, std::map<QString, QString>> *target, const std::map<QString, std::map<QString, QString>> &source);
|
||||
QString createVariable(const QString &name, const QString &defaultValue);
|
||||
DocumentPart *createPart(DocumentComponent *component);
|
||||
DocumentComponent *createComponent(DocumentComponent *parentComponent);
|
||||
DocumentNode *createNode(DocumentPart *part);
|
||||
|
@ -71,6 +72,12 @@ public:
|
|||
QString attribute(DocumentElement *element, const QString &name);
|
||||
void connect(DocumentNode *firstNode, DocumentNode *secondNode);
|
||||
QString &consoleLog();
|
||||
QString createInput(const QString &name, const std::map<QString, QString> &attributes);
|
||||
float createFloatInput(const QString &name, float defaultValue, float minValue, float maxValue);
|
||||
int createIntInput(const QString &name, int defaultValue, int minValue, int maxValue);
|
||||
QColor createColorInput(const QString &name, const QColor &defaultValue);
|
||||
bool createCheckInput(const QString &name, bool checked);
|
||||
int createSelectInput(const QString &name, int defaultSelectedIndex, const QStringList &options);
|
||||
signals:
|
||||
void finished();
|
||||
public slots:
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QDebug>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
#include <QColorDialog>
|
||||
#include "scriptvariableswidget.h"
|
||||
#include "util.h"
|
||||
#include "theme.h"
|
||||
#include "floatnumberwidget.h"
|
||||
#include "intnumberwidget.h"
|
||||
|
||||
ScriptVariablesWidget::ScriptVariablesWidget(const Document *document,
|
||||
QWidget *parent) :
|
||||
|
@ -23,14 +29,157 @@ void ScriptVariablesWidget::reload()
|
|||
QFormLayout *formLayout = new QFormLayout;
|
||||
for (const auto &variable: m_document->variables()) {
|
||||
auto name = variable.first;
|
||||
auto input = valueOfKeyInMapOrEmpty(variable.second, "input");
|
||||
if ("Float" == input) {
|
||||
auto minValue = valueOfKeyInMapOrEmpty(variable.second, "minValue").toFloat();
|
||||
auto maxValue = valueOfKeyInMapOrEmpty(variable.second, "maxValue").toFloat();
|
||||
auto value = valueOfKeyInMapOrEmpty(variable.second, "value").toFloat();
|
||||
qDebug() << "Script variable, name:" << name << "value:" << value;
|
||||
QDoubleSpinBox *inputBox = new QDoubleSpinBox;
|
||||
inputBox->setValue(value);
|
||||
connect(inputBox, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, [=](double toValue) {
|
||||
auto defaultValue = valueOfKeyInMapOrEmpty(variable.second, "defaultValue").toFloat();
|
||||
FloatNumberWidget *floatWidget = new FloatNumberWidget;
|
||||
floatWidget->setItemName(name);
|
||||
floatWidget->setRange(minValue, maxValue);
|
||||
floatWidget->setValue(value);
|
||||
|
||||
connect(floatWidget, &FloatNumberWidget::valueChanged, [=](float toValue) {
|
||||
emit updateVariableValue(name, QString::number(toValue));
|
||||
});
|
||||
formLayout->addRow(name, inputBox);
|
||||
|
||||
QPushButton *floatEraser = new QPushButton(QChar(fa::eraser));
|
||||
Theme::initAwesomeToolButton(floatEraser);
|
||||
|
||||
connect(floatEraser, &QPushButton::clicked, [=]() {
|
||||
floatWidget->setValue(defaultValue);
|
||||
});
|
||||
|
||||
QHBoxLayout *floatLayout = new QHBoxLayout;
|
||||
floatLayout->addWidget(floatEraser);
|
||||
floatLayout->addWidget(floatWidget);
|
||||
|
||||
formLayout->addRow(floatLayout);
|
||||
} else if ("Int" == input) {
|
||||
auto minValue = valueOfKeyInMapOrEmpty(variable.second, "minValue").toInt();
|
||||
auto maxValue = valueOfKeyInMapOrEmpty(variable.second, "maxValue").toInt();
|
||||
auto value = valueOfKeyInMapOrEmpty(variable.second, "value").toInt();
|
||||
auto defaultValue = valueOfKeyInMapOrEmpty(variable.second, "defaultValue").toInt();
|
||||
IntNumberWidget *intWidget = new IntNumberWidget;
|
||||
intWidget->setItemName(name);
|
||||
intWidget->setRange(minValue, maxValue);
|
||||
intWidget->setValue(value);
|
||||
|
||||
connect(intWidget, &IntNumberWidget::valueChanged, [=](int toValue) {
|
||||
emit updateVariableValue(name, QString::number(toValue));
|
||||
});
|
||||
|
||||
QPushButton *intEraser = new QPushButton(QChar(fa::eraser));
|
||||
Theme::initAwesomeToolButton(intEraser);
|
||||
|
||||
connect(intEraser, &QPushButton::clicked, [=]() {
|
||||
intWidget->setValue(defaultValue);
|
||||
});
|
||||
|
||||
QHBoxLayout *intLayout = new QHBoxLayout;
|
||||
intLayout->addWidget(intEraser);
|
||||
intLayout->addWidget(intWidget);
|
||||
|
||||
formLayout->addRow(intLayout);
|
||||
} else if ("Check" == input) {
|
||||
auto value = isTrueValueString(valueOfKeyInMapOrEmpty(variable.second, "value"));
|
||||
auto defaultValue = isTrueValueString(valueOfKeyInMapOrEmpty(variable.second, "defaultValue"));
|
||||
|
||||
QCheckBox *checkBox = new QCheckBox;
|
||||
checkBox->setText(name);
|
||||
checkBox->setChecked(value);
|
||||
|
||||
connect(checkBox, &QCheckBox::stateChanged, [=](int) {
|
||||
emit updateVariableValue(name, checkBox->isChecked() ? "true" : "false");
|
||||
});
|
||||
|
||||
QPushButton *checkEraser = new QPushButton(QChar(fa::eraser));
|
||||
Theme::initAwesomeToolButton(checkEraser);
|
||||
|
||||
connect(checkEraser, &QPushButton::clicked, [=]() {
|
||||
checkBox->setChecked(defaultValue);
|
||||
});
|
||||
|
||||
QHBoxLayout *checkLayout = new QHBoxLayout;
|
||||
checkLayout->addWidget(checkEraser);
|
||||
checkLayout->addWidget(checkBox);
|
||||
|
||||
formLayout->addRow(checkLayout);
|
||||
} else if ("Select" == input) {
|
||||
auto value = valueOfKeyInMapOrEmpty(variable.second, "value").toInt();
|
||||
auto defaultValue = valueOfKeyInMapOrEmpty(variable.second, "defaultValue").toInt();
|
||||
auto length = valueOfKeyInMapOrEmpty(variable.second, "length").toInt();
|
||||
|
||||
QComboBox *selectBox = new QComboBox;
|
||||
selectBox->setEditable(false);
|
||||
selectBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
for (auto i = 0; i < length; ++i) {
|
||||
selectBox->addItem(valueOfKeyInMapOrEmpty(variable.second, "option" + QString::number(i)));
|
||||
}
|
||||
selectBox->setCurrentIndex(value);
|
||||
|
||||
connect(selectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||
emit updateVariableValue(name, QString::number(index));
|
||||
});
|
||||
|
||||
QPushButton *selectEraser = new QPushButton(QChar(fa::eraser));
|
||||
Theme::initAwesomeToolButton(selectEraser);
|
||||
|
||||
connect(selectEraser, &QPushButton::clicked, [=]() {
|
||||
selectBox->setCurrentIndex(defaultValue);
|
||||
});
|
||||
|
||||
QLabel *selectLabel = new QLabel;
|
||||
selectLabel->setText(name);
|
||||
|
||||
QHBoxLayout *selectLayout = new QHBoxLayout;
|
||||
selectLayout->addWidget(selectEraser);
|
||||
selectLayout->addWidget(selectBox);
|
||||
selectLayout->addWidget(selectLabel);
|
||||
|
||||
formLayout->addRow(selectLayout);
|
||||
} else if ("Color" == input) {
|
||||
auto value = valueOfKeyInMapOrEmpty(variable.second, "value");
|
||||
auto defaultValue = valueOfKeyInMapOrEmpty(variable.second, "defaultValue");
|
||||
|
||||
QPushButton *colorEraser = new QPushButton(QChar(fa::eraser));
|
||||
Theme::initAwesomeToolButton(colorEraser);
|
||||
|
||||
QPushButton *pickButton = new QPushButton();
|
||||
Theme::initAwesomeToolButtonWithoutFont(pickButton);
|
||||
|
||||
auto updatePickButtonColor = [=](const QColor &color) {
|
||||
QPalette palette = pickButton->palette();
|
||||
palette.setColor(QPalette::Window, color);
|
||||
palette.setColor(QPalette::Button, color);
|
||||
pickButton->setPalette(palette);
|
||||
};
|
||||
updatePickButtonColor(QColor(value));
|
||||
|
||||
connect(colorEraser, &QPushButton::clicked, [=]() {
|
||||
emit updateVariableValue(name, defaultValue);
|
||||
});
|
||||
|
||||
connect(pickButton, &QPushButton::clicked, [=]() {
|
||||
QColor color = QColorDialog::getColor(value, this);
|
||||
if (color.isValid()) {
|
||||
updatePickButtonColor(color.name());
|
||||
emit updateVariableValue(name, color.name());
|
||||
}
|
||||
});
|
||||
|
||||
QLabel *selectLabel = new QLabel;
|
||||
selectLabel->setText(name);
|
||||
|
||||
QHBoxLayout *colorLayout = new QHBoxLayout;
|
||||
colorLayout->addWidget(colorEraser);
|
||||
colorLayout->addWidget(pickButton);
|
||||
colorLayout->addWidget(selectLabel);
|
||||
colorLayout->addStretch();
|
||||
|
||||
formLayout->addRow(colorLayout);
|
||||
}
|
||||
}
|
||||
widget->setLayout(formLayout);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ ScriptWidget::ScriptWidget(const Document *document, QWidget *parent) :
|
|||
splitter->addWidget(scriptEditWidget);
|
||||
splitter->addWidget(m_consoleEdit);
|
||||
splitter->addWidget(scriptVariablesWidget);
|
||||
splitter->setStretchFactor(2, 1);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(splitter);
|
||||
|
|
|
@ -13632,7 +13632,7 @@ static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
|
|||
return enum_obj;
|
||||
}
|
||||
|
||||
static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
|
||||
JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
|
||||
{
|
||||
JSValue method, ret, sync_iter;
|
||||
|
||||
|
@ -13707,7 +13707,7 @@ static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
|
|||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
|
||||
JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
|
||||
JSValueConst method,
|
||||
int argc, JSValueConst *argv, BOOL *pdone)
|
||||
{
|
||||
|
@ -13898,7 +13898,7 @@ static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
|
|||
int argc, JSValueConst *argv, int magic);
|
||||
|
||||
/* Access an Array's internal JSValue array if available */
|
||||
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
|
||||
int js_get_fast_array(JSContext *ctx, JSValueConst obj,
|
||||
JSValue **arrpp, uint32_t *countp)
|
||||
{
|
||||
/* Try and handle fast arrays explicitly */
|
||||
|
|
|
@ -894,4 +894,8 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
|
|||
#undef js_unlikely
|
||||
#undef js_force_inline
|
||||
|
||||
// https://www.freelists.org/post/quickjs-devel/how-to-iterator-over-a-JSValue-object,1
|
||||
int js_get_fast_array(JSContext *ctx, JSValueConst obj,
|
||||
JSValue **arrpp, uint32_t *countp);
|
||||
|
||||
#endif /* QUICKJS_H */
|
||||
|
|
|
@ -32,7 +32,7 @@ bool ChartPacker::tryPack(float textureSize)
|
|||
std::vector<maxRectsSize> rects;
|
||||
int width = textureSize * m_floatToIntFactor;
|
||||
int height = width;
|
||||
if (m_tryNum > 3) {
|
||||
if (m_tryNum > 50) {
|
||||
qDebug() << "Try the " << m_tryNum << "nth times pack with factor:" << m_textureSizeFactor << " size:" << width << "x" << height;
|
||||
}
|
||||
for (const auto &chartSize: m_chartSizes) {
|
||||
|
|
Loading…
Reference in New Issue