diff --git a/forms/customattributesdialog.ui b/forms/customattributesdialog.ui
new file mode 100644
index 00000000..b61d7150
--- /dev/null
+++ b/forms/customattributesdialog.ui
@@ -0,0 +1,173 @@
+
+
+ CustomAttributesDialog
+
+
+
+ 0
+ 0
+ 410
+ 192
+
+
+
+ Add New Custom Attribute
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Name
+
+
+
+ -
+
+
+ The key name for the new JSON field
+
+
+ true
+
+
+
+ -
+
+
+ Type
+
+
+
+ -
+
+
+ The data type for the new JSON field
+
+
+
+ -
+
+
+ Value
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ The value for the new JSON field
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Add to Defaults
+
+
+
+ -
+
+
+ If checked, this JSON field will be added to any new maps/events of this type, with the current value as its default
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+ NoScrollComboBox
+ QComboBox
+
+
+
+
+
+
diff --git a/include/ui/customattributesdialog.h b/include/ui/customattributesdialog.h
new file mode 100644
index 00000000..749a6691
--- /dev/null
+++ b/include/ui/customattributesdialog.h
@@ -0,0 +1,31 @@
+#ifndef CUSTOMATTRIBUTESDIALOG_H
+#define CUSTOMATTRIBUTESDIALOG_H
+
+#include
+#include
+
+#include "customattributestable.h"
+
+namespace Ui {
+class CustomAttributesDialog;
+}
+
+class CustomAttributesDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CustomAttributesDialog(CustomAttributesTable *parent);
+ ~CustomAttributesDialog();
+
+private:
+ Ui::CustomAttributesDialog *ui;
+ CustomAttributesTable *const table;
+
+ void addNewAttribute();
+ bool verifyName();
+ void setNameEditHighlight(bool highlight);
+};
+
+
+#endif // CUSTOMATTRIBUTESDIALOG_H
diff --git a/include/ui/customattributestable.h b/include/ui/customattributestable.h
index 421ac3bb..8c702470 100644
--- a/include/ui/customattributestable.h
+++ b/include/ui/customattributestable.h
@@ -16,14 +16,19 @@ public:
QMap getAttributes() const;
void setAttributes(const QMap attributes);
+ void addAttribute(QString key, QJsonValue value);
bool deleteSelectedAttributes();
+ void setDefaultAttribute(QString key, QJsonValue value);
+ void unsetDefaultAttribute(QString key);
+
+ const QStringList restrictedKeyNames; // TODO: Populate
+
signals:
void edited();
private:
QTableWidget *table;
- QJsonValue pickType(bool * ok = nullptr);
void addAttribute(QString key, QJsonValue value, bool init);
void resizeVertically();
};
diff --git a/porymap.pro b/porymap.pro
index ddb3f621..3ed1480f 100644
--- a/porymap.pro
+++ b/porymap.pro
@@ -43,6 +43,7 @@ SOURCES += src/core/block.cpp \
src/scriptapi/apiutility.cpp \
src/scriptapi/scripting.cpp \
src/ui/aboutporymap.cpp \
+ src/ui/customattributesdialog.cpp \
src/ui/customscriptseditor.cpp \
src/ui/customscriptslistitem.cpp \
src/ui/draggablepixmapitem.cpp \
@@ -134,6 +135,7 @@ HEADERS += include/core/block.h \
include/lib/orderedmap.h \
include/lib/orderedjson.h \
include/ui/aboutporymap.h \
+ include/ui/customattributesdialog.h \
include/ui/customscriptseditor.h \
include/ui/customscriptslistitem.h \
include/ui/draggablepixmapitem.h \
@@ -214,7 +216,8 @@ FORMS += forms/mainwindow.ui \
forms/colorpicker.ui \
forms/projectsettingseditor.ui \
forms/customscriptseditor.ui \
- forms/customscriptslistitem.ui
+ forms/customscriptslistitem.ui \
+ forms/customattributesdialog.ui
RESOURCES += \
resources/images.qrc \
diff --git a/src/ui/customattributesdialog.cpp b/src/ui/customattributesdialog.cpp
new file mode 100644
index 00000000..b20ebba2
--- /dev/null
+++ b/src/ui/customattributesdialog.cpp
@@ -0,0 +1,96 @@
+#include "customattributesdialog.h"
+#include "ui_customattributesdialog.h"
+
+#include
+
+// Preserve type selection for later dialogs
+static int typeIndex = 0;
+
+CustomAttributesDialog::CustomAttributesDialog(CustomAttributesTable *parent) :
+ QDialog(parent),
+ ui(new Ui::CustomAttributesDialog),
+ table(parent)
+{
+ ui->setupUi(this);
+
+ // Type combo box
+ static const QStringList types = {"String", "Number", "Boolean"};
+ ui->comboBox_Type->addItems(types);
+ ui->comboBox_Type->setEditable(false);
+ connect(ui->comboBox_Type, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) {
+ // When the value type is changed, update the value input widget
+ if (index >= 0 && index < types.length()){
+ ui->stackedWidget_Value->setCurrentIndex(index);
+ typeIndex = index;
+ }
+ });
+ ui->comboBox_Type->setCurrentIndex(typeIndex);
+
+ // Clear the red highlight that may be set if user tries to finish with an invalid key name
+ connect(ui->lineEdit_Name, &QLineEdit::textChanged, [this](QString) {
+ this->setNameEditHighlight(false);
+ });
+
+ // Button box
+ connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton *button) {
+ auto buttonRole = ui->buttonBox->buttonRole(button);
+ if (buttonRole == QDialogButtonBox::AcceptRole && this->verifyName()) {
+ this->addNewAttribute();
+ this->done(QDialog::Accepted);
+ } else if (buttonRole == QDialogButtonBox::RejectRole) {
+ this->done(QDialog::Rejected);
+ }
+ });
+}
+
+CustomAttributesDialog::~CustomAttributesDialog() {
+ delete ui;
+}
+
+void CustomAttributesDialog::setNameEditHighlight(bool highlight) {
+ ui->lineEdit_Name->setStyleSheet(highlight ? "QLineEdit { background-color: rgba(255, 0, 0, 25%) }" : "");
+}
+
+bool CustomAttributesDialog::verifyName() {
+ const QString name = ui->lineEdit_Name->text();
+
+ if (name.isEmpty()) {
+ this->setNameEditHighlight(true);
+ return false;
+ }
+
+ // Invalidate name if it would collide with an expected JSON field name
+ if (this->table->restrictedKeyNames.contains(name)) {
+ const QString msg = QString("The name '%1' is reserved, please choose a different name.").arg(name);
+ QMessageBox::critical(this, "Error", msg);
+ this->setNameEditHighlight(true);
+ return false;
+ }
+
+ // Warn user if key name would overwrite an existing custom attribute
+ if (this->table->getAttributes().keys().contains(name)) {
+ const QString msg = QString("Overwrite value for existing attribute '%1'?").arg(name);
+ if (QMessageBox::warning(this, "Warning", msg, QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel)
+ return false;
+ }
+
+ return true;
+}
+
+void CustomAttributesDialog::addNewAttribute() {
+ QJsonValue value;
+ const QString type = ui->comboBox_Type->currentText();
+ if (type == "String") {
+ value = QJsonValue(ui->lineEdit_Value->text());
+ } else if (type == "Number") {
+ value = QJsonValue(ui->spinBox_Value->value());
+ } else if (type == "Boolean") {
+ value = QJsonValue(ui->checkBox_Value->isChecked());
+ }
+
+ const QString key = ui->lineEdit_Name->text();
+ this->table->addAttribute(key, value);
+
+ if (ui->checkBox_Default->isChecked())
+ this->table->setDefaultAttribute(key, value);
+}
diff --git a/src/ui/customattributestable.cpp b/src/ui/customattributestable.cpp
index a804c85b..547e908c 100644
--- a/src/ui/customattributestable.cpp
+++ b/src/ui/customattributestable.cpp
@@ -1,4 +1,5 @@
#include "customattributestable.h"
+#include "customattributesdialog.h"
#include "parseutil.h"
#include
#include
@@ -41,9 +42,8 @@ CustomAttributesTable::CustomAttributesTable(QWidget *parent) :
connect(addButton, &QPushButton::clicked, [this]() {
bool ok;
- QJsonValue value = this->pickType(&ok);
- if (ok) {
- this->addAttribute("", value, false);
+ CustomAttributesDialog dialog(this);
+ if (dialog.exec() == QDialog::Accepted) {
emit this->edited();
}
});
@@ -63,6 +63,7 @@ CustomAttributesTable::~CustomAttributesTable()
{
}
+// TODO: Fix Header table size on first open
void CustomAttributesTable::resizeVertically() {
int height = 0;
for (int i = 0; i < this->table->rowCount(); i++) {
@@ -118,23 +119,6 @@ QMap CustomAttributesTable::getAttributes() const {
return fields;
}
-QJsonValue CustomAttributesTable::pickType(bool * ok) {
- static const QMap valueTypes = {
- {"String", QJsonValue(QString(""))},
- {"Number", QJsonValue(0)},
- {"Boolean", QJsonValue(false)},
- };
- static const QStringList typeNames = valueTypes.keys();
- static int defaultIndex = typeNames.indexOf("String");
- QString selection = QInputDialog::getItem(this, "", "Choose Value Type", typeNames, defaultIndex, false, ok);
-
- // Preserve selection for next time
- int index = typeNames.indexOf(selection);
- if (index >= 0) defaultIndex = index;
-
- return valueTypes.value(selection);
-}
-
void CustomAttributesTable::setAttributes(const QMap attributes) {
this->table->setRowCount(0);
for (auto it = attributes.cbegin(); it != attributes.cend(); it++)
@@ -142,6 +126,10 @@ void CustomAttributesTable::setAttributes(const QMap attrib
this->resizeVertically();
}
+void CustomAttributesTable::addAttribute(QString key, QJsonValue value) {
+ this->addAttribute(key, value, false);
+}
+
void CustomAttributesTable::addAttribute(QString key, QJsonValue value, bool init) {
const QSignalBlocker blocker(this->table);
QTableWidgetItem * valueItem;
@@ -191,6 +179,14 @@ void CustomAttributesTable::addAttribute(QString key, QJsonValue value, bool ini
}
}
+void CustomAttributesTable::setDefaultAttribute(QString key, QJsonValue value) {
+ // TODO
+}
+
+void CustomAttributesTable::unsetDefaultAttribute(QString key) {
+ // TODO
+}
+
bool CustomAttributesTable::deleteSelectedAttributes() {
int rowCount = this->table->rowCount();
if (rowCount <= 0)