feat(editor): revert value on parse failure + nicer float printing
This commit is contained in:
parent
9cb6327c98
commit
3461198f9a
5 changed files with 62 additions and 16 deletions
|
@ -1,5 +1,7 @@
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
|
#include <ios>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
|
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
|
||||||
Data::CLASS_NAME::~CLASS_NAME() = default; \
|
Data::CLASS_NAME::~CLASS_NAME() = default; \
|
||||||
|
@ -45,7 +47,7 @@ Data::Variant Data::Bool::Deserialize(pugi::xml_node node) {
|
||||||
return Data::Bool(node.text().as_bool());
|
return Data::Bool(node.text().as_bool());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Bool::FromString(std::string string) {
|
std::optional<Data::Variant> Data::Bool::FromString(std::string string) {
|
||||||
return Data::Bool(string[0] == 't' || string[0] == 'T' || string[0] == '1' || string[0] == 'y' || string[0] == 'Y');
|
return Data::Bool(string[0] == 't' || string[0] == 'T' || string[0] == '1' || string[0] == 'y' || string[0] == 'Y');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,21 +60,29 @@ Data::Variant Data::Int::Deserialize(pugi::xml_node node) {
|
||||||
return Data::Int(node.text().as_int());
|
return Data::Int(node.text().as_int());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Int::FromString(std::string string) {
|
std::optional<Data::Variant> Data::Int::FromString(std::string string) {
|
||||||
return Data::Int(std::stoi(string));
|
char* endPos;
|
||||||
|
int value = (int)std::strtol(string.c_str(), &endPos, 10);
|
||||||
|
if (endPos == string.c_str()) return std::nullopt;
|
||||||
|
return Data::Int(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Data::String Data::Float::ToString() const {
|
const Data::String Data::Float::ToString() const {
|
||||||
return Data::String(std::to_string(value));
|
std::stringstream stream;
|
||||||
|
stream << std::noshowpoint << value;
|
||||||
|
return Data::String(stream.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Float::Deserialize(pugi::xml_node node) {
|
Data::Variant Data::Float::Deserialize(pugi::xml_node node) {
|
||||||
return Data::Float(node.text().as_float());
|
return Data::Float(node.text().as_float());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Float::FromString(std::string string) {
|
std::optional<Data::Variant> Data::Float::FromString(std::string string) {
|
||||||
return Data::Float(std::stof(string));
|
char* endPos;
|
||||||
|
float value = std::strtof(string.c_str(), &endPos);
|
||||||
|
if (endPos == string.c_str()) return std::nullopt;
|
||||||
|
return Data::Float(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,6 +94,6 @@ Data::Variant Data::String::Deserialize(pugi::xml_node node) {
|
||||||
return Data::String(node.text().as_string());
|
return Data::String(node.text().as_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::String::FromString(std::string string) {
|
std::optional<Data::Variant> Data::String::FromString(std::string string) {
|
||||||
return Data::String(string);
|
return Data::String(string);
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
#define DEF_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE) class CLASS_NAME : public Data::Base { \
|
#define DEF_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE) class CLASS_NAME : public Data::Base { \
|
||||||
|
@ -16,13 +17,13 @@ public: \
|
||||||
virtual const Data::String ToString() const override; \
|
virtual const Data::String ToString() const override; \
|
||||||
virtual void Serialize(pugi::xml_node node) const override; \
|
virtual void Serialize(pugi::xml_node node) const override; \
|
||||||
static Data::Variant Deserialize(pugi::xml_node node); \
|
static Data::Variant Deserialize(pugi::xml_node node); \
|
||||||
static Data::Variant FromString(std::string); \
|
static std::optional<Data::Variant> FromString(std::string); \
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Variant;
|
class Variant;
|
||||||
typedef std::function<Data::Variant(pugi::xml_node)> Deserializer;
|
typedef std::function<Data::Variant(pugi::xml_node)> Deserializer;
|
||||||
typedef std::function<Data::Variant(std::string)> FromString;
|
typedef std::function<std::optional<Data::Variant>(std::string)> FromString;
|
||||||
|
|
||||||
struct TypeInfo {
|
struct TypeInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -21,7 +21,7 @@ Data::Vector3 Data::Vector3::ONE(1, 1, 1);
|
||||||
|
|
||||||
const Data::String Data::Vector3::ToString() const {
|
const Data::String Data::Vector3::ToString() const {
|
||||||
// https://stackoverflow.com/a/46424921/16255372
|
// https://stackoverflow.com/a/46424921/16255372
|
||||||
std::ostringstream stream;
|
std::stringstream stream;
|
||||||
stream << std::setprecision(8) << std::noshowpoint << X() << ", " << Y() << ", " << Z();
|
stream << std::setprecision(8) << std::noshowpoint << X() << ", " << Y() << ", " << Z();
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
@ -80,11 +80,11 @@ Data::Variant Data::Vector3::Deserialize(pugi::xml_node node) {
|
||||||
return Data::Vector3(node.child("X").text().as_float(), node.child("Y").text().as_float(), node.child("Z").text().as_float());
|
return Data::Vector3(node.child("X").text().as_float(), node.child("Y").text().as_float(), node.child("Z").text().as_float());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Vector3::FromString(std::string string) {
|
std::optional<Data::Variant> Data::Vector3::FromString(std::string string) {
|
||||||
float components[3];
|
float components[3];
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
if (string.length() == 0) return Data::Vector3(0, 0, 0);
|
if (string.length() == 0) return std::nullopt;
|
||||||
while (string[0] == ' ' && string.length() > 0) string.erase(0, 1);
|
while (string[0] == ' ' && string.length() > 0) string.erase(0, 1);
|
||||||
size_t nextPos = string.find(",");
|
size_t nextPos = string.find(",");
|
||||||
if (nextPos == -1) nextPos = string.length();
|
if (nextPos == -1) nextPos = string.length();
|
||||||
|
@ -93,7 +93,7 @@ Data::Variant Data::Vector3::FromString(std::string string) {
|
||||||
|
|
||||||
char* cpos;
|
char* cpos;
|
||||||
float value = std::strtof(term.c_str(), &cpos);
|
float value = std::strtof(term.c_str(), &cpos);
|
||||||
if (cpos == term.c_str()) return Data::Vector3(0, 0, 0);
|
if (cpos == term.c_str()) return std::nullopt;
|
||||||
|
|
||||||
components[i] = value;
|
components[i] = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Data {
|
||||||
virtual void Serialize(pugi::xml_node node) const override;
|
virtual void Serialize(pugi::xml_node node) const override;
|
||||||
|
|
||||||
static Data::Variant Deserialize(pugi::xml_node node);
|
static Data::Variant Deserialize(pugi::xml_node node);
|
||||||
static Data::Variant FromString(std::string);
|
static std::optional<Data::Variant> FromString(std::string);
|
||||||
|
|
||||||
operator glm::vec3() const;
|
operator glm::vec3() const;
|
||||||
operator rp::Vector3() const;
|
operator rp::Vector3() const;
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
|
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
|
||||||
if (index.column() == 0) return nullptr;
|
if (index.column() == 0) return nullptr;
|
||||||
|
|
||||||
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return nullptr;
|
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return nullptr;
|
||||||
|
@ -84,6 +84,35 @@ public:
|
||||||
editor->setGeometry(option.rect.adjusted(-view->indentation(), 0, -view->indentation(), 0));
|
editor->setGeometry(option.rect.adjusted(-view->indentation(), 0, -view->indentation(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
|
||||||
|
if (index.column() == 0) return;
|
||||||
|
|
||||||
|
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return;
|
||||||
|
InstanceRef inst = view->currentInstance->lock();
|
||||||
|
|
||||||
|
std::string propertyName = view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString();
|
||||||
|
PropertyMeta meta = inst->GetPropertyMeta(propertyName).value();
|
||||||
|
Data::Variant currentValue = inst->GetPropertyValue(propertyName).value();
|
||||||
|
|
||||||
|
if (meta.type == &Data::Float::TYPE) {
|
||||||
|
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
|
||||||
|
|
||||||
|
spinBox->setValue(currentValue.get<Data::Float>());
|
||||||
|
} else if (meta.type == &Data::Int::TYPE) {
|
||||||
|
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
|
||||||
|
|
||||||
|
spinBox->setValue(currentValue.get<Data::Int>());
|
||||||
|
} else if (meta.type == &Data::String::TYPE) {
|
||||||
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||||
|
|
||||||
|
lineEdit->setText(QString::fromStdString((std::string)currentValue.get<Data::String>()));
|
||||||
|
} else if (meta.type->fromString) {
|
||||||
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||||
|
|
||||||
|
lineEdit->setText(QString::fromStdString((std::string)currentValue.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
|
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
|
||||||
if (index.column() == 0) return;
|
if (index.column() == 0) return;
|
||||||
|
|
||||||
|
@ -97,18 +126,24 @@ public:
|
||||||
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
|
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
|
||||||
|
|
||||||
inst->SetPropertyValue(propertyName, Data::Float((float)spinBox->value()));
|
inst->SetPropertyValue(propertyName, Data::Float((float)spinBox->value()));
|
||||||
|
model->setData(index, spinBox->value());
|
||||||
} else if (meta.type == &Data::Int::TYPE) {
|
} else if (meta.type == &Data::Int::TYPE) {
|
||||||
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
|
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
|
||||||
|
|
||||||
inst->SetPropertyValue(propertyName, Data::Int((float)spinBox->value()));
|
inst->SetPropertyValue(propertyName, Data::Int((float)spinBox->value()));
|
||||||
|
model->setData(index, spinBox->value());
|
||||||
} else if (meta.type == &Data::String::TYPE) {
|
} else if (meta.type == &Data::String::TYPE) {
|
||||||
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||||
|
|
||||||
inst->SetPropertyValue(propertyName, Data::String(lineEdit->text().toStdString()));
|
inst->SetPropertyValue(propertyName, Data::String(lineEdit->text().toStdString()));
|
||||||
|
model->setData(index, lineEdit->text());
|
||||||
} else if (meta.type->fromString) {
|
} else if (meta.type->fromString) {
|
||||||
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
|
||||||
|
|
||||||
inst->SetPropertyValue(propertyName, meta.type->fromString(lineEdit->text().toStdString()));
|
std::optional<Data::Variant> parsedResult = meta.type->fromString(lineEdit->text().toStdString());
|
||||||
|
if (!parsedResult) return;
|
||||||
|
inst->SetPropertyValue(propertyName, parsedResult.value());
|
||||||
|
model->setData(index, QString::fromStdString(parsedResult.value().ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue