diff --git a/forms/customattributesdialog.ui b/forms/customattributesdialog.ui
new file mode 100644
index 00000000..b1f1ee4b
--- /dev/null
+++ b/forms/customattributesdialog.ui
@@ -0,0 +1,172 @@
+
+
+ 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
+
+ -
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ color: rgb(255, 0, 0)
+
+
+
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok
+
+
+
+
+
+
+
+ NoScrollComboBox
+ QComboBox
+
+
+
+
+
+
diff --git a/forms/customattributesframe.ui b/forms/customattributesframe.ui
new file mode 100644
index 00000000..87619e63
--- /dev/null
+++ b/forms/customattributesframe.ui
@@ -0,0 +1,89 @@
+
+
+ CustomAttributesFrame
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ -
+
+
+ Custom Attributes
+
+
+
+ -
+
+
+ QFrame::Shape::NoFrame
+
+
+ QFrame::Shadow::Plain
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Add
+
+
+
+ -
+
+
+ false
+
+
+ Delete
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ CustomAttributesTable
+ QTableWidget
+
+
+
+
+
+
diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui
index dfea9752..4a9e439a 100644
--- a/forms/mainwindow.ui
+++ b/forms/mainwindow.ui
@@ -2244,113 +2244,69 @@
-
-
+
- QFrame::Shape::StyledPanel
+ QFrame::Shape::NoFrame
- QFrame::Shadow::Raised
+ QFrame::Shadow::Plain
-
-
-
-
-
- Custom Fields
-
-
-
- -
-
-
- QFrame::Shape::NoFrame
-
-
- QFrame::Shadow::Plain
-
-
-
- 0
+
+ true
+
+
+
+
+ 0
+ 0
+ 1011
+ 806
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
-
- 0
+
+ QFrame::Shape::StyledPanel
-
- 0
+
+ QFrame::Shadow::Raised
-
- 0
+
+
+ -
+
+
+ Qt::Orientation::Vertical
-
-
-
-
- Add
-
-
-
- -
-
-
- Delete
-
-
-
- -
-
-
- Qt::Orientation::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- -
-
-
- Custom fields will be added to the map.json file for the current map.
-
-
- false
-
-
- false
-
-
- true
-
-
- false
-
-
- true
-
-
- false
-
-
-
- Type
+
+
+ 1
+ 767
+
-
-
-
- Key
-
-
-
-
- Value
-
-
-
-
-
+
+
+
+
@@ -3349,6 +3305,12 @@
1
+
+ CustomAttributesFrame
+ QFrame
+
+ 1
+
diff --git a/include/core/events.h b/include/core/events.h
index c0a5a625..081ff506 100644
--- a/include/core/events.h
+++ b/include/core/events.h
@@ -160,10 +160,10 @@ public:
virtual void setDefaultValues(Project *project);
virtual QSet getExpectedFields() = 0;
- void readCustomValues(QJsonObject values);
- void addCustomValuesTo(OrderedJson::object *obj);
- const QMap getCustomValues() { return this->customValues; }
- void setCustomValues(const QMap newCustomValues) { this->customValues = newCustomValues; }
+ void readCustomAttributes(const QJsonObject &json);
+ void addCustomAttributesTo(OrderedJson::object *obj) const;
+ const QMap getCustomAttributes() const { return this->customAttributes; }
+ void setCustomAttributes(const QMap newCustomAttributes) { this->customAttributes = newCustomAttributes; }
virtual void loadPixmap(Project *project);
@@ -206,7 +206,7 @@ protected:
int spriteHeight = 16;
bool usingSprite = false;
- QMap customValues;
+ QMap customAttributes;
QPixmap pixmap;
DraggablePixmapItem *pixmapItem = nullptr;
diff --git a/include/editor.h b/include/editor.h
index 434415e9..81bf1611 100644
--- a/include/editor.h
+++ b/include/editor.h
@@ -107,7 +107,7 @@ public:
void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false);
void updateSecondaryTileset(QString tilesetLabel, bool forceLoad = false);
void toggleBorderVisibility(bool visible, bool enableScriptCallback = true);
- void updateCustomMapHeaderValues(QTableWidget *);
+ void updateCustomMapAttributes();
DraggablePixmapItem *addMapEvent(Event *event);
bool eventLimitReached(Map *, Event::Type);
diff --git a/include/mainwindow.h b/include/mainwindow.h
index cf37a298..42d346f3 100644
--- a/include/mainwindow.h
+++ b/include/mainwindow.h
@@ -274,9 +274,6 @@ private slots:
void on_actionAbout_Porymap_triggered();
void on_actionOpen_Log_File_triggered();
void on_actionOpen_Config_Folder_triggered();
- void on_pushButton_AddCustomHeaderField_clicked();
- void on_pushButton_DeleteCustomHeaderField_clicked();
- void on_tableWidget_CustomHeaderFields_cellChanged(int row, int column);
void on_horizontalSlider_MetatileZoom_valueChanged(int value);
void on_horizontalSlider_CollisionZoom_valueChanged(int value);
void on_pushButton_NewWildMonGroup_clicked();
@@ -406,7 +403,7 @@ private:
Event::Group getEventGroupFromTabWidget(QWidget *tab);
bool closeSupplementaryWindows();
void setWindowDisabled(bool);
-
+ void resetMapCustomAttributesTable();
void initTilesetEditor();
bool initRegionMapEditor(bool silent = false);
bool askToFixRegionMapEditor();
diff --git a/include/ui/customattributesdialog.h b/include/ui/customattributesdialog.h
new file mode 100644
index 00000000..7048e16c
--- /dev/null
+++ b/include/ui/customattributesdialog.h
@@ -0,0 +1,34 @@
+#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 *table);
+ ~CustomAttributesDialog();
+
+private:
+ Ui::CustomAttributesDialog *ui;
+ CustomAttributesTable *const m_table;
+
+ void setInputType(int inputType);
+ void onNameChanged(const QString &);
+ bool validateName(bool allowEmpty = false);
+ void clickedButton(QAbstractButton *button);
+ void addNewAttribute();
+ QVariant getValue() const;
+};
+
+
+#endif // CUSTOMATTRIBUTESDIALOG_H
diff --git a/include/ui/customattributesframe.h b/include/ui/customattributesframe.h
new file mode 100644
index 00000000..f19d0601
--- /dev/null
+++ b/include/ui/customattributesframe.h
@@ -0,0 +1,36 @@
+#ifndef CUSTOMATTRIBUTESFRAME_H
+#define CUSTOMATTRIBUTESFRAME_H
+
+/*
+ The frame containing the Custom Attributes table and its Add/Delete buttons.
+ Shared by the map's Header tab and Events.
+*/
+
+#include "customattributestable.h"
+
+#include
+#include
+
+namespace Ui {
+class CustomAttributesFrame;
+}
+
+class CustomAttributesFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ explicit CustomAttributesFrame(QWidget *parent = nullptr);
+ ~CustomAttributesFrame();
+
+ CustomAttributesTable* table() const;
+
+private:
+ Ui::CustomAttributesFrame *ui;
+
+ void addAttribute();
+ void deleteAttribute();
+ void updateDeleteButton();
+};
+
+#endif // CUSTOMATTRIBUTESFRAME_H
diff --git a/include/ui/customattributestable.h b/include/ui/customattributestable.h
index f17f4877..21cac4de 100644
--- a/include/ui/customattributestable.h
+++ b/include/ui/customattributestable.h
@@ -1,25 +1,44 @@
#ifndef CUSTOMATTRIBUTESTABLE_H
#define CUSTOMATTRIBUTESTABLE_H
-#include "events.h"
#include
-#include
+#include
#include
-class CustomAttributesTable : public QFrame
+class CustomAttributesTable : public QTableWidget
{
-public:
- explicit CustomAttributesTable(Event *event, QWidget *parent = nullptr);
- ~CustomAttributesTable();
+ Q_OBJECT
- static const QMap getAttributes(QTableWidget * table);
- static QJsonValue pickType(QWidget * parent, bool * ok = nullptr);
- static void addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew = false);
- static bool deleteSelectedAttributes(QTableWidget * table);
+public:
+ explicit CustomAttributesTable(QWidget *parent = nullptr);
+ ~CustomAttributesTable() {};
+
+ QMap getAttributes() const;
+ void setAttributes(const QMap &attributes);
+
+ void addNewAttribute(const QString &key, const QJsonValue &value);
+ bool deleteSelectedAttributes();
+
+ bool isEmpty() const;
+ bool isSelectionEmpty() const;
+
+ QSet keys() const { return m_keys; }
+ QSet restrictedKeys() const { return m_restrictedKeys; }
+ void setRestrictedKeys(const QSet &keys) { m_restrictedKeys = keys; }
+
+signals:
+ void edited();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *event) override;
private:
- Event *event;
- QTableWidget *table;
+ QSet m_keys; // All keys currently in the table
+ QSet m_restrictedKeys; // All keys not allowed in the table
+
+ QPair getAttribute(int row) const;
+ int addAttribute(const QString &key, const QJsonValue &value);
+ void removeAttribute(const QString &key);
void resizeVertically();
};
diff --git a/include/ui/eventframes.h b/include/ui/eventframes.h
index c11cf8e6..2ad55750 100644
--- a/include/ui/eventframes.h
+++ b/include/ui/eventframes.h
@@ -52,6 +52,8 @@ public:
QFrame *frame_contents;
QVBoxLayout *layout_contents;
+ CustomAttributesFrame *custom_attributes;
+
protected:
bool populated = false;
bool initialized = false;
diff --git a/porymap.pro b/porymap.pro
index b6758c2e..76d19d21 100644
--- a/porymap.pro
+++ b/porymap.pro
@@ -67,6 +67,8 @@ SOURCES += src/core/advancemapparser.cpp \
src/ui/aboutporymap.cpp \
src/ui/colorinputwidget.cpp \
src/ui/connectionslistitem.cpp \
+ src/ui/customattributesdialog.cpp \
+ src/ui/customattributestable.cpp \
src/ui/customscriptseditor.cpp \
src/ui/customscriptslistitem.cpp \
src/ui/divingmappixmapitem.cpp \
@@ -83,7 +85,7 @@ SOURCES += src/core/advancemapparser.cpp \
src/ui/regionmaplayoutpixmapitem.cpp \
src/ui/regionmapentriespixmapitem.cpp \
src/ui/cursortilerect.cpp \
- src/ui/customattributestable.cpp \
+ src/ui/customattributesframe.cpp \
src/ui/eventframes.cpp \
src/ui/eventfilters.cpp \
src/ui/filterchildrenproxymodel.cpp \
@@ -176,6 +178,8 @@ HEADERS += include/core/advancemapparser.h \
include/lib/orderedjson.h \
include/ui/aboutporymap.h \
include/ui/connectionslistitem.h \
+ include/ui/customattributesdialog.h \
+ include/ui/customattributestable.h \
include/ui/customscriptseditor.h \
include/ui/customscriptslistitem.h \
include/ui/divingmappixmapitem.h \
@@ -192,7 +196,7 @@ HEADERS += include/core/advancemapparser.h \
include/ui/regionmaplayoutpixmapitem.h \
include/ui/regionmapentriespixmapitem.h \
include/ui/cursortilerect.h \
- include/ui/customattributestable.h \
+ include/ui/customattributesframe.h \
include/ui/eventframes.h \
include/ui/eventfilters.h \
include/ui/filterchildrenproxymodel.h \
@@ -258,6 +262,7 @@ HEADERS += include/core/advancemapparser.h \
FORMS += forms/mainwindow.ui \
forms/colorinputwidget.ui \
forms/connectionslistitem.ui \
+ forms/customattributesframe.ui \
forms/gridsettingsdialog.ui \
forms/mapheaderform.ui \
forms/maplisttoolbar.ui \
@@ -282,6 +287,7 @@ FORMS += forms/mainwindow.ui \
forms/projectsettingseditor.ui \
forms/customscriptseditor.ui \
forms/customscriptslistitem.ui \
+ forms/customattributesdialog.ui \
forms/updatepromoter.ui \
forms/wildmonchart.ui \
forms/wildmonsearch.ui
diff --git a/src/core/events.cpp b/src/core/events.cpp
index c0cf7b7a..2da13da0 100644
--- a/src/core/events.cpp
+++ b/src/core/events.cpp
@@ -53,20 +53,20 @@ void Event::setDefaultValues(Project *) {
this->setElevation(projectConfig.defaultElevation);
}
-void Event::readCustomValues(QJsonObject values) {
- this->customValues.clear();
- QSet expectedFields = this->getExpectedFields();
- for (QString key : values.keys()) {
- if (!expectedFields.contains(key)) {
- this->customValues[key] = values[key];
+void Event::readCustomAttributes(const QJsonObject &json) {
+ this->customAttributes.clear();
+ const QSet expectedFields = this->getExpectedFields();
+ for (auto i = json.constBegin(); i != json.constEnd(); i++) {
+ if (!expectedFields.contains(i.key())) {
+ this->customAttributes[i.key()] = i.value();
}
}
}
-void Event::addCustomValuesTo(OrderedJson::object *obj) {
- for (QString key : this->customValues.keys()) {
- if (!obj->contains(key)) {
- (*obj)[key] = OrderedJson::fromQJsonValue(this->customValues[key]);
+void Event::addCustomAttributesTo(OrderedJson::object *obj) const {
+ for (auto i = this->customAttributes.constBegin(); i != this->customAttributes.constEnd(); i++) {
+ if (!obj->contains(i.key())) {
+ (*obj)[i.key()] = OrderedJson::fromQJsonValue(i.value());
}
}
}
@@ -197,7 +197,7 @@ Event *ObjectEvent::duplicate() {
copy->setSightRadiusBerryTreeID(this->getSightRadiusBerryTreeID());
copy->setScript(this->getScript());
copy->setFlag(this->getFlag());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -227,7 +227,7 @@ OrderedJson::object ObjectEvent::buildEventJson(Project *) {
objectJson["trainer_sight_or_berry_tree_id"] = this->getSightRadiusBerryTreeID();
objectJson["script"] = this->getScript();
objectJson["flag"] = this->getFlag();
- this->addCustomValuesTo(&objectJson);
+ this->addCustomAttributesTo(&objectJson);
return objectJson;
}
@@ -245,7 +245,7 @@ bool ObjectEvent::loadFromJson(QJsonObject json, Project *) {
this->setScript(ParseUtil::jsonToQString(json["script"]));
this->setFlag(ParseUtil::jsonToQString(json["flag"]));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -371,7 +371,7 @@ Event *CloneObjectEvent::duplicate() {
copy->setGfx(this->getGfx());
copy->setTargetID(this->getTargetID());
copy->setTargetMap(this->getTargetMap());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -394,7 +394,7 @@ OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) {
cloneJson["target_local_id"] = this->getTargetID();
const QString mapName = this->getTargetMap();
cloneJson["target_map"] = project->mapNamesToMapConstants.value(mapName, mapName);
- this->addCustomValuesTo(&cloneJson);
+ this->addCustomAttributesTo(&cloneJson);
return cloneJson;
}
@@ -411,7 +411,7 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
logWarn(QString("Unknown Target Map constant '%1'.").arg(mapConstant));
this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -478,7 +478,7 @@ Event *WarpEvent::duplicate() {
copy->setDestinationMap(this->getDestinationMap());
copy->setDestinationWarpID(this->getDestinationWarpID());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -501,7 +501,7 @@ OrderedJson::object WarpEvent::buildEventJson(Project *project) {
warpJson["dest_map"] = project->mapNamesToMapConstants.value(mapName, mapName);
warpJson["dest_warp_id"] = this->getDestinationWarpID();
- this->addCustomValuesTo(&warpJson);
+ this->addCustomAttributesTo(&warpJson);
return warpJson;
}
@@ -518,7 +518,7 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) {
logWarn(QString("Unknown Destination Map constant '%1'.").arg(mapConstant));
this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -560,7 +560,7 @@ Event *TriggerEvent::duplicate() {
copy->setScriptVarValue(this->getScriptVarValue());
copy->setScriptLabel(this->getScriptLabel());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -584,7 +584,7 @@ OrderedJson::object TriggerEvent::buildEventJson(Project *) {
triggerJson["var_value"] = this->getScriptVarValue();
triggerJson["script"] = this->getScriptLabel();
- this->addCustomValuesTo(&triggerJson);
+ this->addCustomAttributesTo(&triggerJson);
return triggerJson;
}
@@ -597,7 +597,7 @@ bool TriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setScriptVarValue(ParseUtil::jsonToQString(json["var_value"]));
this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -634,7 +634,7 @@ Event *WeatherTriggerEvent::duplicate() {
copy->setElevation(this->getElevation());
copy->setWeather(this->getWeather());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -656,7 +656,7 @@ OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) {
weatherJson["elevation"] = this->getElevation();
weatherJson["weather"] = this->getWeather();
- this->addCustomValuesTo(&weatherJson);
+ this->addCustomAttributesTo(&weatherJson);
return weatherJson;
}
@@ -667,7 +667,7 @@ bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setWeather(ParseUtil::jsonToQString(json["weather"]));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -701,7 +701,7 @@ Event *SignEvent::duplicate() {
copy->setFacingDirection(this->getFacingDirection());
copy->setScriptLabel(this->getScriptLabel());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -724,7 +724,7 @@ OrderedJson::object SignEvent::buildEventJson(Project *) {
signJson["player_facing_dir"] = this->getFacingDirection();
signJson["script"] = this->getScriptLabel();
- this->addCustomValuesTo(&signJson);
+ this->addCustomAttributesTo(&signJson);
return signJson;
}
@@ -736,7 +736,7 @@ bool SignEvent::loadFromJson(QJsonObject json, Project *) {
this->setFacingDirection(ParseUtil::jsonToQString(json["player_facing_dir"]));
this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -774,7 +774,7 @@ Event *HiddenItemEvent::duplicate() {
copy->setQuantity(this->getQuantity());
copy->setQuantity(this->getQuantity());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -803,7 +803,7 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) {
hiddenItemJson["underfoot"] = this->getUnderfoot();
}
- this->addCustomValuesTo(&hiddenItemJson);
+ this->addCustomAttributesTo(&hiddenItemJson);
return hiddenItemJson;
}
@@ -821,7 +821,7 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"]));
}
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
@@ -867,7 +867,7 @@ Event *SecretBaseEvent::duplicate() {
copy->setElevation(this->getElevation());
copy->setBaseID(this->getBaseID());
- copy->setCustomValues(this->getCustomValues());
+ copy->setCustomAttributes(this->getCustomAttributes());
return copy;
}
@@ -889,7 +889,7 @@ OrderedJson::object SecretBaseEvent::buildEventJson(Project *) {
secretBaseJson["elevation"] = this->getElevation();
secretBaseJson["secret_base_id"] = this->getBaseID();
- this->addCustomValuesTo(&secretBaseJson);
+ this->addCustomAttributesTo(&secretBaseJson);
return secretBaseJson;
}
@@ -900,7 +900,7 @@ bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) {
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setBaseID(ParseUtil::jsonToQString(json["secret_base_id"]));
- this->readCustomValues(json);
+ this->readCustomAttributes(json);
return true;
}
diff --git a/src/editor.cpp b/src/editor.cpp
index f3fb1c99..3c7fee27 100644
--- a/src/editor.cpp
+++ b/src/editor.cpp
@@ -10,7 +10,7 @@
#include "editcommands.h"
#include "config.h"
#include "scripting.h"
-#include "customattributestable.h"
+#include "customattributesframe.h"
#include "validator.h"
#include
#include
@@ -52,6 +52,7 @@ Editor::Editor(Ui::MainWindow* ui)
connect(ui->toolButton_Open_Scripts, &QToolButton::pressed, this, &Editor::openMapScripts);
connect(ui->actionOpen_Project_in_Text_Editor, &QAction::triggered, this, &Editor::openProjectInTextEditor);
connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, this, &Editor::toggleGrid);
+ connect(ui->mapCustomAttributesFrame->table(), &CustomAttributesTable::edited, this, &Editor::updateCustomMapAttributes);
}
Editor::~Editor()
@@ -1975,9 +1976,9 @@ void Editor::updateBorderVisibility() {
}
}
-void Editor::updateCustomMapHeaderValues(QTableWidget *table)
+void Editor::updateCustomMapAttributes()
{
- map->setCustomAttributes(CustomAttributesTable::getAttributes(table));
+ map->setCustomAttributes(ui->mapCustomAttributesFrame->table()->getAttributes());
map->modify();
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index bf9a91e8..d0ba8040 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -7,7 +7,7 @@
#include "eventframes.h"
#include "bordermetatilespixmapitem.h"
#include "currentselectedmetatilespixmapitem.h"
-#include "customattributestable.h"
+#include "customattributesframe.h"
#include "scripting.h"
#include "adjustingstackedwidget.h"
#include "draggablepixmapitem.h"
@@ -1033,16 +1033,7 @@ void MainWindow::displayMapProperties() {
ui->comboBox_PrimaryTileset->setCurrentText(editor->map->layout()->tileset_primary_label);
ui->comboBox_SecondaryTileset->setCurrentText(editor->map->layout()->tileset_secondary_label);
-
- // Custom fields table.
-/* // TODO: Re-enable
- ui->tableWidget_CustomHeaderFields->blockSignals(true);
- ui->tableWidget_CustomHeaderFields->setRowCount(0);
- for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++)
- CustomAttributesTable::addAttribute(ui->tableWidget_CustomHeaderFields, it.key(), it.value());
- ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- ui->tableWidget_CustomHeaderFields->blockSignals(false);
-*/
+ ui->mapCustomAttributesFrame->table()->setAttributes(editor->map->customAttributes());
}
void MainWindow::on_comboBox_LayoutSelector_currentTextChanged(const QString &text) {
@@ -1119,6 +1110,8 @@ bool MainWindow::setProjectUI() {
this->layoutListProxyModel->setSourceModel(this->layoutTreeModel);
ui->layoutList->setModel(layoutListProxyModel);
+ ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->topLevelMapFields);
+
return true;
}
@@ -2867,27 +2860,6 @@ void MainWindow::reloadScriptEngine() {
Scripting::cb_MapOpened(editor->map->name()); // TODO: API should have equivalent for layout
}
-void MainWindow::on_pushButton_AddCustomHeaderField_clicked()
-{
- bool ok;
- QJsonValue value = CustomAttributesTable::pickType(this, &ok);
- if (ok){
- CustomAttributesTable::addAttribute(this->ui->tableWidget_CustomHeaderFields, "", value, true);
- this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
- }
-}
-
-void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked()
-{
- if (CustomAttributesTable::deleteSelectedAttributes(this->ui->tableWidget_CustomHeaderFields))
- this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
-}
-
-void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int)
-{
- this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
-}
-
void MainWindow::on_horizontalSlider_MetatileZoom_valueChanged(int value) {
porymapConfig.metatilesZoom = value;
double scale = pow(3.0, static_cast(value - 30) / 30.0);
diff --git a/src/project.cpp b/src/project.cpp
index 712ee87f..9e0a8c3a 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -353,14 +353,13 @@ bool Project::loadMapData(Map* map) {
}
}
- // Check for custom fields
-/* // TODO: Re-enable
- for (QString key : mapObj.keys()) {
- if (!this->topLevelMapFields.contains(key)) {
- map->customHeaders.insert(key, mapObj[key]);
+ QMap customAttributes;
+ for (auto i = mapObj.constBegin(); i != mapObj.constEnd(); i++) {
+ if (!this->topLevelMapFields.contains(i.key())) {
+ customAttributes.insert(i.key(), i.value());
}
}
-*/
+ map->setCustomAttributes(customAttributes);
return true;
}
@@ -1338,11 +1337,10 @@ void Project::saveMap(Map *map) {
}
// Custom header fields.
-/* // TODO: Re-enable
- for (QString key : map->customHeaders.keys()) {
- mapObj[key] = OrderedJson::fromQJsonValue(map->customHeaders[key]);
+ const auto customAttributes = map->customAttributes();
+ for (auto i = customAttributes.constBegin(); i != customAttributes.constEnd(); i++) {
+ mapObj[i.key()] = OrderedJson::fromQJsonValue(i.value());
}
-*/
OrderedJson mapJson(mapObj);
OrderedJsonDoc jsonDoc(&mapJson);
diff --git a/src/ui/customattributesdialog.cpp b/src/ui/customattributesdialog.cpp
new file mode 100644
index 00000000..7b4a4b84
--- /dev/null
+++ b/src/ui/customattributesdialog.cpp
@@ -0,0 +1,101 @@
+#include "customattributesdialog.h"
+#include "ui_customattributesdialog.h"
+
+#include
+
+static int curInputType = 0;
+
+CustomAttributesDialog::CustomAttributesDialog(CustomAttributesTable *table) :
+ QDialog(table),
+ ui(new Ui::CustomAttributesDialog),
+ m_table(table)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ ui->setupUi(this);
+
+ // Type combo box
+ ui->comboBox_Type->addItems({"String", "Number", "Boolean"});
+ ui->comboBox_Type->setEditable(false);
+
+ // When the value type is changed, update the value input widget
+ connect(ui->comboBox_Type, QOverload::of(&QComboBox::currentIndexChanged), this, &CustomAttributesDialog::setInputType);
+ ui->comboBox_Type->setCurrentIndex(curInputType);
+
+ ui->spinBox_Value->setMinimum(INT_MIN);
+ ui->spinBox_Value->setMaximum(INT_MAX);
+
+ connect(ui->lineEdit_Name, &QLineEdit::textChanged, this, &CustomAttributesDialog::onNameChanged);
+ connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &CustomAttributesDialog::clickedButton);
+
+ adjustSize();
+}
+
+CustomAttributesDialog::~CustomAttributesDialog() {
+ delete ui;
+}
+
+void CustomAttributesDialog::setInputType(int inputType) {
+ if (inputType < 0 || inputType >= ui->stackedWidget_Value->count())
+ return;
+
+ ui->stackedWidget_Value->setCurrentIndex(inputType);
+
+ // Preserve input widget for later dialogs
+ curInputType = inputType;
+}
+
+void CustomAttributesDialog::onNameChanged(const QString &) {
+ validateName(true);
+}
+
+bool CustomAttributesDialog::validateName(bool allowEmpty) {
+ const QString name = ui->lineEdit_Name->text();
+
+ QString errorText;
+ if (name.isEmpty()) {
+ if (!allowEmpty) errorText = QString("%1 cannot be empty.").arg(ui->label_Name->text());
+ } else if (m_table->restrictedKeys().contains(name)) {
+ errorText = QString("The name '%1' is reserved, please choose a different name.").arg(name);
+ }
+
+ bool isValid = errorText.isEmpty();
+ ui->label_NameError->setText(errorText);
+ ui->label_NameError->setVisible(!isValid);
+ ui->lineEdit_Name->setStyleSheet(!isValid ? "QLineEdit { background-color: rgba(255, 0, 0, 25%) }" : "");
+ return isValid;
+}
+
+QVariant CustomAttributesDialog::getValue() const {
+ QVariant value;
+ auto widget = ui->stackedWidget_Value->currentWidget();
+ if (widget == ui->page_String) {
+ value = QVariant(ui->lineEdit_Value->text());
+ } else if (widget == ui->page_Number) {
+ value = QVariant(ui->spinBox_Value->value());
+ } else if (widget == ui->page_Boolean) {
+ value = QVariant(ui->checkBox_Value->isChecked());
+ }
+ return value;
+}
+
+void CustomAttributesDialog::addNewAttribute() {
+ m_table->addNewAttribute(ui->lineEdit_Name->text(), QJsonValue::fromVariant(getValue()));
+}
+
+void CustomAttributesDialog::clickedButton(QAbstractButton *button) {
+ auto buttonRole = ui->buttonBox->buttonRole(button);
+ if (buttonRole == QDialogButtonBox::AcceptRole && validateName()) {
+ const QString key = ui->lineEdit_Name->text();
+ if (m_table->keys().contains(key)) {
+ // Warn user if key name would overwrite an existing custom attribute
+ const QString msg = QString("Overwrite value for existing attribute '%1'?").arg(key);
+ if (QMessageBox::warning(this, "Warning", msg, QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel){
+ return;
+ }
+ }
+ addNewAttribute();
+ done(QDialog::Accepted);
+ } else if (buttonRole == QDialogButtonBox::RejectRole) {
+ done(QDialog::Rejected);
+ }
+}
diff --git a/src/ui/customattributesframe.cpp b/src/ui/customattributesframe.cpp
new file mode 100644
index 00000000..e9cb6663
--- /dev/null
+++ b/src/ui/customattributesframe.cpp
@@ -0,0 +1,39 @@
+#include "customattributesframe.h"
+#include "ui_customattributesframe.h"
+#include "customattributesdialog.h"
+#include
+#include
+#include
+
+CustomAttributesFrame::CustomAttributesFrame(QWidget *parent) :
+ QFrame(parent),
+ ui(new Ui::CustomAttributesFrame)
+{
+ ui->setupUi(this);
+
+ connect(ui->button_Add, &QPushButton::clicked, this, &CustomAttributesFrame::addAttribute);
+ connect(ui->button_Delete, &QPushButton::clicked, this, &CustomAttributesFrame::deleteAttribute);
+ connect(ui->tableWidget, &CustomAttributesTable::itemSelectionChanged, this, &CustomAttributesFrame::updateDeleteButton);
+ connect(ui->tableWidget, &CustomAttributesTable::edited, this, &CustomAttributesFrame::updateDeleteButton);
+}
+
+CustomAttributesFrame::~CustomAttributesFrame() {
+ delete ui;
+}
+
+CustomAttributesTable* CustomAttributesFrame::table() const {
+ return ui->tableWidget;
+}
+
+void CustomAttributesFrame::addAttribute() {
+ auto dialog = new CustomAttributesDialog(ui->tableWidget);
+ dialog->open();
+}
+
+void CustomAttributesFrame::deleteAttribute() {
+ ui->tableWidget->deleteSelectedAttributes();
+}
+
+void CustomAttributesFrame::updateDeleteButton() {
+ ui->button_Delete->setDisabled(ui->tableWidget->isSelectionEmpty());
+}
diff --git a/src/ui/customattributestable.cpp b/src/ui/customattributestable.cpp
index d87b3f8a..65381443 100644
--- a/src/ui/customattributestable.cpp
+++ b/src/ui/customattributestable.cpp
@@ -1,196 +1,176 @@
#include "customattributestable.h"
#include "parseutil.h"
-#include
+#include "noscrollspinbox.h"
#include
-#include
-#include
-#include
#include
-#include
-CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
- QFrame(parent)
+enum Column {
+ Key,
+ Value,
+ Count
+};
+
+enum DataRole {
+ JsonType = Qt::UserRole,
+ OriginalValue,
+};
+
+CustomAttributesTable::CustomAttributesTable(QWidget *parent) :
+ QTableWidget(parent)
{
- this->event = event;
+ this->setColumnCount(Column::Count);
+ this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ this->setHorizontalHeaderLabels(QStringList({"Key", "Value"}));
+ this->horizontalHeader()->setStretchLastSection(true);
+ this->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+ this->horizontalHeader()->setVisible(false);
+ this->verticalHeader()->setVisible(false);
- QVBoxLayout *layout = new QVBoxLayout(this);
- QLabel *label = new QLabel("Custom Attributes");
- layout->addWidget(label);
+ connect(this, &QTableWidget::cellChanged, this, &CustomAttributesTable::edited);
- QFrame *buttonsFrame = new QFrame(this);
- buttonsFrame->setLayout(new QHBoxLayout());
- QPushButton *addButton = new QPushButton(this);
- QPushButton *deleteButton = new QPushButton(this);
- addButton->setText("Add");
- deleteButton->setText("Delete");
- buttonsFrame->layout()->addWidget(addButton);
- buttonsFrame->layout()->addWidget(deleteButton);
- buttonsFrame->layout()->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed));
- buttonsFrame->layout()->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(buttonsFrame);
-
- this->table = new QTableWidget(this);
- this->table->setColumnCount(3);
- this->table->setHorizontalHeaderLabels(QStringList({"Type", "Key", "Value"}));
- this->table->horizontalHeader()->setStretchLastSection(true);
- layout->addWidget(this->table);
-
- QMap customValues = this->event->getCustomValues();
- for (auto it = customValues.begin(); it != customValues.end(); it++)
- CustomAttributesTable::addAttribute(this->table, it.key(), it.value());
-
- connect(addButton, &QPushButton::clicked, [=]() {
- bool ok;
- QJsonValue value = CustomAttributesTable::pickType(this, &ok);
- if (ok){
- CustomAttributesTable::addAttribute(this->table, "", value, true);
- this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
- this->resizeVertically();
+ // Key cells are uneditable, but users should be allowed to select one and press delete to remove the row.
+ // Adding the "Selectable" flag to the Key cell changes its appearance to match the Value cell, which
+ // makes it confusing that you can't edit the Key cell. To keep the uneditable appearance and allow
+ // deleting rows by selecting Key cells, we select the full row when a Key cell is selected.
+ connect(this, &QTableWidget::cellPressed, [this](int row, int column) {
+ if (column == Column::Key) {
+ this->selectRow(row);
}
});
-
- connect(deleteButton, &QPushButton::clicked, [=]() {
- if (CustomAttributesTable::deleteSelectedAttributes(this->table)) {
- this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
- this->resizeVertically();
- }
- });
-
- connect(this->table, &QTableWidget::cellChanged, [=]() {
- this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
- });
-
- this->resizeVertically();
}
-CustomAttributesTable::~CustomAttributesTable()
-{
-}
-
-void CustomAttributesTable::resizeVertically() {
- int horizontalHeaderHeight = this->table->horizontalHeader()->height();
- int rowHeight = 0;
- for (int i = 0; i < this->table->rowCount(); i++) {
- rowHeight += this->table->rowHeight(0);
- }
- int totalHeight = horizontalHeaderHeight + rowHeight;
- if (this->table->rowCount() == 0) {
- totalHeight += 1;
- } else {
- totalHeight += 2;
- }
- this->table->setMinimumHeight(totalHeight);
- this->table->setMaximumHeight(totalHeight);
-}
-
-const QMap CustomAttributesTable::getAttributes(QTableWidget * table) {
+QMap CustomAttributesTable::getAttributes() const {
QMap fields;
- if (!table) return fields;
-
- for (int row = 0; row < table->rowCount(); row++) {
- QString key = "";
- QTableWidgetItem *typeItem = table->item(row, 0);
- QTableWidgetItem *keyItem = table->item(row, 1);
- QTableWidgetItem *valueItem = table->item(row, 2);
-
- if (keyItem) key = keyItem->text();
- if (key.isEmpty() || !typeItem || !valueItem)
- continue;
-
- // Read from the table data which JSON type to save the value as
- QJsonValue::Type type = static_cast(typeItem->data(Qt::UserRole).toInt());
- QJsonValue value;
- switch (type)
- {
- case QJsonValue::String:
- value = QJsonValue(valueItem->text());
- break;
- case QJsonValue::Double:
- value = QJsonValue(valueItem->text().toInt());
- break;
- case QJsonValue::Bool:
- value = QJsonValue(valueItem->checkState() == Qt::Checked);
- break;
- default:
- // All other types will just be preserved
- value = valueItem->data(Qt::UserRole).toJsonValue();
- break;
- }
- fields[key] = value;
+ for (int row = 0; row < this->rowCount(); row++) {
+ auto keyValuePair = this->getAttribute(row);
+ if (!keyValuePair.first.isEmpty())
+ fields[keyValuePair.first] = keyValuePair.second;
}
return fields;
}
-QJsonValue CustomAttributesTable::pickType(QWidget * parent, bool * ok) {
- const QMap valueTypes = {
- {"String", QJsonValue(QString(""))},
- {"Number", QJsonValue(0)},
- {"Boolean", QJsonValue(false)},
- };
- QStringList typeNames = valueTypes.keys();
- QString selection = QInputDialog::getItem(parent, "", "Choose Value Type", typeNames, typeNames.indexOf("String"), false, ok);
- return valueTypes.value(selection);
+QPair CustomAttributesTable::getAttribute(int row) const {
+ auto keyItem = this->item(row, Column::Key);
+ if (!keyItem)
+ return {};
+
+ // Read from the table data which JSON type to save the value as
+ QJsonValue::Type type = static_cast(keyItem->data(DataRole::JsonType).toInt());
+
+ QJsonValue value;
+ if (type == QJsonValue::String) {
+ value = QJsonValue(this->item(row, Column::Value)->text());
+ } else if (type == QJsonValue::Double) {
+ auto spinBox = static_cast(this->cellWidget(row, Column::Value));
+ value = QJsonValue(spinBox->value());
+ } else if (type == QJsonValue::Bool) {
+ value = QJsonValue(this->item(row, Column::Value)->checkState() == Qt::Checked);
+ } else {
+ // All other types will just be preserved
+ value = this->item(row, Column::Value)->data(DataRole::OriginalValue).toJsonValue();
+ }
+
+ return {keyItem->text(), value};
}
-void CustomAttributesTable::addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew) {
- if (!table) return;
- QTableWidgetItem * valueItem;
+int CustomAttributesTable::addAttribute(const QString &key, const QJsonValue &value) {
+ // Stop 'edited' signals from being emitted before we finish creating the new table data.
+ const QSignalBlocker blocker(this);
+
+ // Certain key names cannot be used (if they would overwrite a field used outside this table)
+ if (m_restrictedKeys.contains(key))
+ return -1;
+
+ // Overwrite existing key (if present)
+ if (m_keys.contains(key))
+ this->removeAttribute(key);
+
+ // Add new row
+ int rowIndex = this->rowCount();
+ this->insertRow(rowIndex);
+
QJsonValue::Type type = value.type();
- switch (type)
- {
- case QJsonValue::String:
- case QJsonValue::Double:
- valueItem = new QTableWidgetItem(ParseUtil::jsonToQString(value));
+
+ // Add key name to table
+ auto keyItem = new QTableWidgetItem(key);
+ keyItem->setFlags(Qt::ItemIsEnabled);
+ keyItem->setData(DataRole::JsonType, type); // Record the type for writing to the file
+ keyItem->setTextAlignment(Qt::AlignCenter);
+ keyItem->setToolTip(key); // Display name as tool tip in case it's too long to see in the cell
+ this->setItem(rowIndex, Column::Key, keyItem);
+
+ // Add value to table
+ switch (type) {
+ case QJsonValue::String: {
+ // Add a regular cell item for editing text
+ this->setItem(rowIndex, Column::Value, new QTableWidgetItem(ParseUtil::jsonToQString(value)));
break;
- case QJsonValue::Bool:
- valueItem = new QTableWidgetItem("");
+ } case QJsonValue::Double: {
+ // Add a spin box for editing number values
+ auto spinBox = new NoScrollSpinBox(this);
+ spinBox->setMinimum(INT_MIN);
+ spinBox->setMaximum(INT_MAX);
+ spinBox->setValue(ParseUtil::jsonToInt(value));
+ // This connection will be handled by QTableWidget::cellChanged for other cell types
+ connect(spinBox, QOverload::of(&QSpinBox::valueChanged), this, &CustomAttributesTable::edited);
+ this->setCellWidget(rowIndex, Column::Value, spinBox);
+ break;
+ } case QJsonValue::Bool: {
+ // Add a checkable cell item for editing bools
+ auto valueItem = new QTableWidgetItem("");
valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked);
valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+ this->setItem(rowIndex, Column::Value, valueItem);
break;
- default:
- valueItem = new QTableWidgetItem("This value cannot be edited from this table");
- valueItem->setFlags(Qt::ItemIsSelectable);
- valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file
+ } default: {
+ // Arrays, objects, or null/undefined values cannot be edited
+ auto valueItem = new QTableWidgetItem("This value cannot be edited from this table");
+ valueItem->setFlags(Qt::NoItemFlags);
+ valueItem->setData(DataRole::OriginalValue, value); // Preserve the value for writing to the file
+ this->setItem(rowIndex, Column::Value, valueItem);
break;
- }
+ }}
+ m_keys.insert(key);
- const QHash typeToName = {
- {QJsonValue::Bool, "Bool"},
- {QJsonValue::Double, "Number"},
- {QJsonValue::String, "String"},
- {QJsonValue::Array, "Array"},
- {QJsonValue::Object, "Object"},
- {QJsonValue::Null, "Null"},
- {QJsonValue::Undefined, "Null"},
- };
- QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]);
- typeItem->setFlags(Qt::ItemIsEnabled);
- typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file
- typeItem->setTextAlignment(Qt::AlignCenter);
+ return rowIndex;
+}
- int rowIndex = table->rowCount();
- table->insertRow(rowIndex);
- table->setItem(rowIndex, 0, typeItem);
- table->setItem(rowIndex, 1, new QTableWidgetItem(key));
- table->setItem(rowIndex, 2, valueItem);
+// For the user adding an attribute by interacting with the table
+void CustomAttributesTable::addNewAttribute(const QString &key, const QJsonValue &value) {
+ int row = this->addAttribute(key, value);
+ if (row < 0) return;
+ this->resizeVertically();
+ this->selectRow(row);
+ emit this->edited();
+}
- if (isNew) {
- valueItem->setText(""); // Erase the "0" in new numbers
- table->selectRow(rowIndex);
+// For programmatically populating the table
+void CustomAttributesTable::setAttributes(const QMap &attributes) {
+ m_keys.clear();
+ this->setRowCount(0); // Clear old values
+ for (auto it = attributes.cbegin(); it != attributes.cend(); it++)
+ this->addAttribute(it.key(), it.value());
+ this->resizeVertically();
+}
+
+void CustomAttributesTable::removeAttribute(const QString &key) {
+ for (int row = 0; row < this->rowCount(); row++) {
+ auto keyItem = this->item(row, Column::Key);
+ if (keyItem && keyItem->text() == key) {
+ m_keys.remove(key);
+ this->removeRow(row);
+ break;
+ }
}
}
-bool CustomAttributesTable::deleteSelectedAttributes(QTableWidget * table) {
- if (!table)
+bool CustomAttributesTable::deleteSelectedAttributes() {
+ if (this->isEmpty())
return false;
- int rowCount = table->rowCount();
- if (rowCount <= 0)
- return false;
-
- QModelIndexList indexList = table->selectionModel()->selectedIndexes();
+ QModelIndexList indexList = this->selectionModel()->selectedIndexes();
QList persistentIndexes;
- for (QModelIndex index : indexList) {
+ for (const auto &index : indexList) {
QPersistentModelIndex persistentIndex(index);
persistentIndexes.append(persistentIndex);
}
@@ -198,12 +178,51 @@ bool CustomAttributesTable::deleteSelectedAttributes(QTableWidget * table) {
if (persistentIndexes.isEmpty())
return false;
- for (QPersistentModelIndex index : persistentIndexes) {
- table->removeRow(index.row());
+ for (const auto &index : persistentIndexes) {
+ auto row = index.row();
+ auto item = this->item(row, Column::Key);
+ if (item) m_keys.remove(item->text());
+ this->removeRow(row);
}
+ this->resizeVertically();
- if (table->rowCount() > 0) {
- table->selectRow(0);
+ if (this->rowCount() > 0) {
+ this->selectRow(0);
}
+ emit this->edited();
return true;
}
+
+void CustomAttributesTable::resizeVertically() {
+ int height = 0;
+ if (this->isEmpty()) {
+ // Hide header when table is empty
+ this->horizontalHeader()->setVisible(false);
+ } else {
+ for (int i = 0; i < this->rowCount(); i++)
+ height += this->rowHeight(i);
+
+ // Account for header and horizontal scroll bar
+ this->horizontalHeader()->setVisible(true);
+ height += this->horizontalHeader()->height();
+ if (this->horizontalScrollBar()->isVisible())
+ height += this->horizontalScrollBar()->height();
+ height += 2; // Border
+ }
+
+ this->setMinimumHeight(height);
+ this->setMaximumHeight(height);
+}
+
+void CustomAttributesTable::resizeEvent(QResizeEvent *event) {
+ QTableWidget::resizeEvent(event);
+ this->resizeVertically();
+}
+
+bool CustomAttributesTable::isEmpty() const {
+ return this->rowCount() <= 0;
+}
+
+bool CustomAttributesTable::isSelectionEmpty() const {
+ return this->selectedIndexes().isEmpty();
+}
diff --git a/src/ui/eventframes.cpp b/src/ui/eventframes.cpp
index cb06fea1..61794c41 100644
--- a/src/ui/eventframes.cpp
+++ b/src/ui/eventframes.cpp
@@ -1,5 +1,5 @@
#include "eventframes.h"
-#include "customattributestable.h"
+#include "customattributesframe.h"
#include "editcommands.h"
#include "draggablepixmapitem.h"
@@ -97,8 +97,9 @@ void EventFrame::setup() {
}
void EventFrame::initCustomAttributesTable() {
- CustomAttributesTable *customAttributes = new CustomAttributesTable(this->event, this);
- this->layout_contents->addWidget(customAttributes);
+ this->custom_attributes = new CustomAttributesFrame(this);
+ this->custom_attributes->table()->setRestrictedKeys(this->event->getExpectedFields());
+ this->layout_contents->addWidget(this->custom_attributes);
}
void EventFrame::connectSignals(MainWindow *) {
@@ -128,6 +129,12 @@ void EventFrame::connectSignals(MainWindow *) {
this->event->setZ(value);
this->event->modify();
});
+
+ this->custom_attributes->disconnect();
+ connect(this->custom_attributes->table(), &CustomAttributesTable::edited, [this]() {
+ this->event->setCustomAttributes(this->custom_attributes->table()->getAttributes());
+ this->event->modify();
+ });
}
void EventFrame::initialize() {
@@ -139,6 +146,8 @@ void EventFrame::initialize() {
this->spinner_y->setValue(this->event->getY());
this->spinner_z->setValue(this->event->getZ());
+ this->custom_attributes->table()->setAttributes(this->event->getCustomAttributes());
+
this->label_icon->setPixmap(this->event->getPixmap());
}