Combine minor creation dialogs

This commit is contained in:
GriffinR 2024-12-10 18:22:22 -05:00
parent 391f7b1685
commit 52a7cd4f56
8 changed files with 275 additions and 117 deletions

View File

@ -170,14 +170,30 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_PrimaryTilesetError">
<property name="visible">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0)</string>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_SecondaryTileset">
<property name="text">
<string>Secondary</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="NoScrollComboBox" name="comboBox_SecondaryTileset">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The secondary tileset for the new map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -190,8 +206,8 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_TilesetsError">
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_SecondaryTilesetError">
<property name="visible">
<bool>false</bool>
</property>

82
forms/newnamedialog.ui Normal file
View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewNameDialog</class>
<widget class="QDialog" name="NewNameDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>252</width>
<height>87</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="form">
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Plain</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_Name">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_Name">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_NameError">
<property name="visible">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0)</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -33,7 +33,8 @@ private:
Project *m_project;
bool validateMapDimensions();
bool validateTilesets();
bool validatePrimaryTileset(bool allowEmpty = false);
bool validateSecondaryTileset(bool allowEmpty = false);
};
#endif // NEWLAYOUTFORM_H

View File

@ -0,0 +1,42 @@
#ifndef NEWNAMEDIALOG_H
#define NEWNAMEDIALOG_H
/*
This is a generic dialog for requesting a new unique name from the user.
*/
#include <QDialog>
#include <QAbstractButton>
class Project;
namespace Ui {
class NewNameDialog;
}
class NewNameDialog : public QDialog
{
Q_OBJECT
public:
explicit NewNameDialog(const QString &label, Project *project, QWidget *parent = nullptr);
~NewNameDialog();
void setNamePrefix(const QString &prefix);
virtual void accept() override;
signals:
void applied(const QString &newName);
private:
Ui::NewNameDialog *ui;
Project *project = nullptr;
const QString symbolPrefix;
bool validateName(bool allowEmpty = false);
void onNameChanged(const QString &name);
void dialogButtonClicked(QAbstractButton *button);
};
#endif // NEWNAMEDIALOG_H

View File

@ -91,6 +91,7 @@ SOURCES += src/core/advancemapparser.cpp \
src/ui/neweventtoolbutton.cpp \
src/ui/newlayoutdialog.cpp \
src/ui/newlayoutform.cpp \
src/ui/newnamedialog.cpp \
src/ui/noscrollcombobox.cpp \
src/ui/noscrollspinbox.cpp \
src/ui/montabwidget.cpp \
@ -197,6 +198,7 @@ HEADERS += include/core/advancemapparser.h \
include/ui/neweventtoolbutton.h \
include/ui/newlayoutdialog.h \
include/ui/newlayoutform.h \
include/ui/newnamedialog.h \
include/ui/noscrollcombobox.h \
include/ui/noscrollspinbox.h \
include/ui/montabwidget.h \
@ -243,6 +245,7 @@ FORMS += forms/mainwindow.ui \
forms/maplisttoolbar.ui \
forms/newlayoutdialog.ui \
forms/newlayoutform.ui \
forms/newnamedialog.ui \
forms/newmapconnectiondialog.ui \
forms/prefabcreationdialog.ui \
forms/prefabframe.ui \

View File

@ -26,6 +26,7 @@
#include "newmapdialog.h"
#include "newlayoutdialog.h"
#include "newtilesetdialog.h"
#include "newnamedialog.h"
#include <QClipboard>
#include <QDirIterator>
@ -1310,90 +1311,16 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
}
void MainWindow::mapListAddGroup() {
QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::ApplicationModal);
QDialogButtonBox newItemButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
connect(&newItemButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
QLineEdit *newNameEdit = new QLineEdit(&dialog);
newNameEdit->setClearButtonEnabled(true);
static const QRegularExpression re_validChars("[A-Za-z_]+[\\w]*");
newNameEdit->setValidator(new QRegularExpressionValidator(re_validChars, newNameEdit));
QLabel *errorMessageLabel = new QLabel(&dialog);
errorMessageLabel->setVisible(false);
errorMessageLabel->setStyleSheet("QLabel { background-color: rgba(255, 0, 0, 25%) }");
connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){
const QString mapGroupName = newNameEdit->text();
if (!this->editor->project->isIdentifierUnique(mapGroupName)) {
errorMessageLabel->setText(QString("The name '%1' is not unique.").arg(mapGroupName));
errorMessageLabel->setVisible(true);
} else {
dialog.accept();
}
});
QFormLayout form(&dialog);
form.addRow("New Group Name", newNameEdit);
form.addRow("", errorMessageLabel);
form.addRow(&newItemButtonBox);
if (dialog.exec() == QDialog::Accepted) {
QString newFieldName = newNameEdit->text();
if (newFieldName.isEmpty()) return;
this->editor->project->addNewMapGroup(newFieldName);
}
auto dialog = new NewNameDialog("New Group Name", this->editor->project, this);
connect(dialog, &NewNameDialog::applied, this->editor->project, &Project::addNewMapGroup);
dialog->open();
}
void MainWindow::mapListAddArea() {
QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::ApplicationModal);
QDialogButtonBox newItemButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
connect(&newItemButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
// TODO: This would be a little more seamless with a single line edit that enforces the MAPSEC prefix, rather than a separate label for the actual name.
const QString prefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix);
auto newNameEdit = new QLineEdit(&dialog);
auto newNameDisplay = new QLabel(&dialog);
newNameDisplay->setText(prefix);
connect(newNameEdit, &QLineEdit::textEdited, [newNameDisplay, prefix] (const QString &text) {
// As the user types a name, update the label to show the name with the prefix.
newNameDisplay->setText(prefix + text);
});
QLabel *errorMessageLabel = new QLabel(&dialog);
errorMessageLabel->setVisible(false);
errorMessageLabel->setStyleSheet("QLabel { background-color: rgba(255, 0, 0, 25%) }");
static const QRegularExpression re_validChars("[A-Za-z_]+[\\w]*");
newNameEdit->setValidator(new QRegularExpressionValidator(re_validChars, newNameEdit));
connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){
const QString newAreaName = newNameDisplay->text();
if (!this->editor->project->isIdentifierUnique(newAreaName)) {
errorMessageLabel->setText(QString("The name '%1' is not unique.").arg(newAreaName));
errorMessageLabel->setVisible(true);
} else {
dialog.accept();
}
});
QLabel *newNameEditLabel = new QLabel("New Area Name", &dialog);
QLabel *newNameDisplayLabel = new QLabel("Constant Name", &dialog);
QFormLayout form(&dialog);
form.addRow(newNameEditLabel, newNameEdit);
form.addRow(newNameDisplayLabel, newNameDisplay);
form.addRow("", errorMessageLabel);
form.addRow(&newItemButtonBox);
if (dialog.exec() == QDialog::Accepted) {
if (newNameEdit->text().isEmpty()) return;
this->editor->project->addNewMapsec(newNameDisplay->text());
}
auto dialog = new NewNameDialog("New Area Name", this->editor->project, this);
dialog->setNamePrefix(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix));
connect(dialog, &NewNameDialog::applied, this->editor->project, &Project::addNewMapsec);
dialog->open();
}
void MainWindow::onNewMapCreated(Map *newMap, const QString &groupName) {

View File

@ -12,12 +12,14 @@ NewLayoutForm::NewLayoutForm(QWidget *parent)
ui->groupBox_BorderDimensions->setVisible(projectConfig.useCustomBorderSize);
// TODO: Read from project?
ui->spinBox_BorderWidth->setMaximum(MAX_BORDER_WIDTH);
ui->spinBox_BorderHeight->setMaximum(MAX_BORDER_HEIGHT);
connect(ui->spinBox_MapWidth, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();});
connect(ui->spinBox_MapHeight, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){validateMapDimensions();});
connect(ui->spinBox_MapWidth, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); });
connect(ui->spinBox_MapHeight, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); });
connect(ui->comboBox_PrimaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validatePrimaryTileset(true); });
connect(ui->comboBox_SecondaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validateSecondaryTileset(true); });
}
NewLayoutForm::~NewLayoutForm()
@ -71,12 +73,12 @@ Layout::Settings NewLayoutForm::settings() const {
return settings;
}
// TODO: Validate while typing
bool NewLayoutForm::validate() {
// Make sure to call each validation function so that all errors are shown at once.
bool valid = true;
if (!validateMapDimensions()) valid = false;
if (!validateTilesets()) valid = false;
if (!validatePrimaryTileset()) valid = false;
if (!validateSecondaryTileset()) valid = false;
return valid;
}
@ -84,11 +86,17 @@ bool NewLayoutForm::validateMapDimensions() {
int size = m_project->getMapDataSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value());
int maxSize = m_project->getMaxMapDataSize();
// TODO: Get from project
const int additionalWidth = 15;
const int additionalHeight = 14;
QString errorText;
if (size > maxSize) {
errorText = QString("The specified width and height are too large.\n"
"The maximum map width and height is the following: (width + 15) * (height + 14) <= %1\n"
"The specified map width and height was: (%2 + 15) * (%3 + 14) = %4")
"The maximum map width and height is the following: (width + %1) * (height + %2) <= %3\n"
"The specified map width and height was: (%4 + %1) * (%5 + %2) = %6")
.arg(additionalWidth)
.arg(additionalHeight)
.arg(maxSize)
.arg(ui->spinBox_MapWidth->value())
.arg(ui->spinBox_MapHeight->value())
@ -101,33 +109,36 @@ bool NewLayoutForm::validateMapDimensions() {
return isValid;
}
bool NewLayoutForm::validateTilesets() {
QString primaryTileset = ui->comboBox_PrimaryTileset->currentText();
QString secondaryTileset = ui->comboBox_SecondaryTileset->currentText();
bool NewLayoutForm::validatePrimaryTileset(bool allowEmpty) {
const QString name = ui->comboBox_PrimaryTileset->currentText();
QString primaryErrorText;
if (primaryTileset.isEmpty()) {
primaryErrorText = QString("The primary tileset cannot be empty.");
} else if (ui->comboBox_PrimaryTileset->findText(primaryTileset) < 0) {
primaryErrorText = QString("The specified primary tileset '%1' does not exist.").arg(primaryTileset);
QString errorText;
if (name.isEmpty()) {
if (!allowEmpty) errorText = QString("The Primary Tileset cannot be empty.");
} else if (ui->comboBox_PrimaryTileset->findText(name) < 0) {
errorText = QString("The Primary Tileset '%1' does not exist.").arg(ui->label_PrimaryTileset->text()).arg(name);
}
QString secondaryErrorText;
if (secondaryTileset.isEmpty()) {
secondaryErrorText = QString("The secondary tileset cannot be empty.");
} else if (ui->comboBox_SecondaryTileset->findText(secondaryTileset) < 0) {
secondaryErrorText = QString("The specified secondary tileset '%2' does not exist.").arg(secondaryTileset);
}
QString errorText = QString("%1%2%3")
.arg(primaryErrorText)
.arg(!primaryErrorText.isEmpty() ? "\n" : "")
.arg(secondaryErrorText);
bool isValid = errorText.isEmpty();
ui->label_TilesetsError->setText(errorText);
ui->label_TilesetsError->setVisible(!isValid);
ui->comboBox_PrimaryTileset->lineEdit()->setStyleSheet(!primaryErrorText.isEmpty() ? lineEdit_ErrorStylesheet : "");
ui->comboBox_SecondaryTileset->lineEdit()->setStyleSheet(!secondaryErrorText.isEmpty() ? lineEdit_ErrorStylesheet : "");
ui->label_PrimaryTilesetError->setText(errorText);
ui->label_PrimaryTilesetError->setVisible(!isValid);
ui->comboBox_PrimaryTileset->lineEdit()->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : "");
return isValid;
}
bool NewLayoutForm::validateSecondaryTileset(bool allowEmpty) {
const QString name = ui->comboBox_SecondaryTileset->currentText();
QString errorText;
if (name.isEmpty()) {
if (!allowEmpty) errorText = QString("The Secondary Tileset cannot be empty.");
} else if (ui->comboBox_SecondaryTileset->findText(name) < 0) {
errorText = QString("The Secondary Tileset '%1' does not exist.").arg(name);
}
bool isValid = errorText.isEmpty();
ui->label_SecondaryTilesetError->setText(errorText);
ui->label_SecondaryTilesetError->setVisible(!isValid);
ui->comboBox_SecondaryTileset->lineEdit()->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : "");
return isValid;
}

76
src/ui/newnamedialog.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "newnamedialog.h"
#include "ui_newnamedialog.h"
#include "project.h"
#include "imageexport.h"
const QString lineEdit_ErrorStylesheet = "QLineEdit { background-color: rgba(255, 0, 0, 25%) }";
NewNameDialog::NewNameDialog(const QString &label, Project* project, QWidget *parent) :
QDialog(parent),
ui(new Ui::NewNameDialog)
{
setAttribute(Qt::WA_DeleteOnClose);
setModal(true);
ui->setupUi(this);
this->project = project;
if (!label.isEmpty())
ui->label_Name->setText(label);
// Identifiers must only contain word characters, and cannot start with a digit.
static const QRegularExpression expression("[A-Za-z_]+[\\w]*");
QRegularExpressionValidator *validator = new QRegularExpressionValidator(expression, this);
ui->lineEdit_Name->setValidator(validator);
connect(ui->lineEdit_Name, &QLineEdit::textChanged, this, &NewNameDialog::onNameChanged);
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewNameDialog::dialogButtonClicked);
adjustSize();
}
NewNameDialog::~NewNameDialog()
{
delete ui;
}
void NewNameDialog::setNamePrefix(const QString &) {
//TODO
}
void NewNameDialog::onNameChanged(const QString &) {
validateName(true);
}
bool NewNameDialog::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 (!this->project->isIdentifierUnique(name)) {
errorText = QString("%1 '%2' is not unique.").arg(ui->label_Name->text()).arg(name);
}
bool isValid = errorText.isEmpty();
ui->label_NameError->setText(errorText);
ui->label_NameError->setVisible(!isValid);
ui->lineEdit_Name->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : "");
return isValid;
}
void NewNameDialog::dialogButtonClicked(QAbstractButton *button) {
auto role = ui->buttonBox->buttonRole(button);
if (role == QDialogButtonBox::RejectRole){
reject();
} else if (role == QDialogButtonBox::AcceptRole) {
accept();
}
}
void NewNameDialog::accept() {
if (!validateName())
return;
emit applied(ui->lineEdit_Name->text());
QDialog::accept();
}