create 'add layout' button
This commit is contained in:
parent
963b09c866
commit
22b4108a7f
7 changed files with 213 additions and 22 deletions
|
@ -69,6 +69,17 @@ public:
|
|||
|
||||
QUndoStack editHistory;
|
||||
|
||||
// to simplify new layout settings transfer between functions
|
||||
struct SimpleSettings {
|
||||
QString id;
|
||||
QString name;
|
||||
int width;
|
||||
int height;
|
||||
QString tileset_primary_label;
|
||||
QString tileset_secondary_label;
|
||||
QString from_id = QString();
|
||||
};
|
||||
|
||||
public:
|
||||
Layout *copy();
|
||||
void copyFrom(Layout *other);
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
bool loadMapData(Map*);
|
||||
bool readMapLayouts();
|
||||
Layout *loadLayout(QString layoutId);
|
||||
Layout *createNewLayout(Layout::SimpleSettings &layoutSettings);
|
||||
bool loadLayout(Layout *);
|
||||
bool loadMapLayout(Map*);
|
||||
bool loadLayoutTilesets(Layout *);
|
||||
|
@ -235,8 +236,8 @@ public:
|
|||
private:
|
||||
void updateLayout(Layout *);
|
||||
|
||||
void setNewMapBlockdata(Map* map);
|
||||
void setNewMapBorder(Map *map);
|
||||
void setNewLayoutBlockdata(Layout *layout);
|
||||
void setNewLayoutBorder(Layout *layout);
|
||||
void setNewMapEvents(Map *map);
|
||||
void setNewMapConnections(Map *map);
|
||||
|
||||
|
|
|
@ -155,6 +155,7 @@ public:
|
|||
QStandardItem *createLayoutItem(QString layoutId);
|
||||
QStandardItem *createMapItem(QString mapName);
|
||||
|
||||
QStandardItem *insertLayoutItem(QString layoutId);
|
||||
QStandardItem *insertMapItem(QString mapName, QString layoutId);
|
||||
|
||||
QStandardItem *getItem(const QModelIndex &index) const;
|
||||
|
|
|
@ -74,6 +74,7 @@ void Editor::save() {
|
|||
}
|
||||
else if (this->project && this->layout) {
|
||||
this->project->saveLayout(this->layout);
|
||||
this->project->saveAllDataStructures();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1309,7 +1309,121 @@ void MainWindow::mapListAddGroup() {
|
|||
}
|
||||
|
||||
void MainWindow::mapListAddLayout() {
|
||||
// this->layoutTreeModel->insertMapItem(newMapName, newMap->layout->id);
|
||||
if (!editor || !editor->project) return;
|
||||
|
||||
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-z0-9]*$");
|
||||
QRegularExpressionValidator *validator = new QRegularExpressionValidator(re_validChars);
|
||||
newNameEdit->setValidator(validator);
|
||||
|
||||
QLabel *newId = new QLabel("LAYOUT_", &dialog);
|
||||
connect(newNameEdit, &QLineEdit::textChanged, [&](QString text){
|
||||
newId->setText(Layout::layoutConstantFromName(text.remove("_Layout")));
|
||||
});
|
||||
|
||||
NoScrollComboBox *useExistingCombo = new NoScrollComboBox(&dialog);
|
||||
useExistingCombo->addItems(this->editor->project->mapLayoutsTable);
|
||||
useExistingCombo->setEnabled(false);
|
||||
|
||||
QCheckBox *useExistingCheck = new QCheckBox(&dialog);
|
||||
|
||||
QLabel *errorMessageLabel = new QLabel(&dialog);
|
||||
errorMessageLabel->setVisible(false);
|
||||
errorMessageLabel->setStyleSheet("QLabel { background-color: rgba(255, 0, 0, 25%) }");
|
||||
QString errorMessage;
|
||||
|
||||
QComboBox *primaryCombo = new QComboBox(&dialog);
|
||||
primaryCombo->addItems(this->editor->project->primaryTilesetLabels);
|
||||
QComboBox *secondaryCombo = new QComboBox(&dialog);
|
||||
secondaryCombo->addItems(this->editor->project->secondaryTilesetLabels);
|
||||
|
||||
QSpinBox *widthSpin = new QSpinBox(&dialog);
|
||||
QSpinBox *heightSpin = new QSpinBox(&dialog);
|
||||
|
||||
widthSpin->setMinimum(1);
|
||||
heightSpin->setMinimum(1);
|
||||
widthSpin->setMaximum(this->editor->project->getMaxMapWidth());
|
||||
heightSpin->setMaximum(this->editor->project->getMaxMapHeight());
|
||||
|
||||
connect(useExistingCheck, &QCheckBox::stateChanged, [&](int state){
|
||||
bool useExisting = (state == Qt::Checked);
|
||||
useExistingCombo->setEnabled(useExisting);
|
||||
primaryCombo->setEnabled(!useExisting);
|
||||
secondaryCombo->setEnabled(!useExisting);
|
||||
widthSpin->setEnabled(!useExisting);
|
||||
heightSpin->setEnabled(!useExisting);
|
||||
});
|
||||
|
||||
QFormLayout form(&dialog);
|
||||
form.addRow("New Layout Name", newNameEdit);
|
||||
form.addRow("New Layout ID", newId);
|
||||
form.addRow("Copy Existing Layout", useExistingCheck);
|
||||
form.addRow("", useExistingCombo);
|
||||
form.addRow("Primary Tileset", primaryCombo);
|
||||
form.addRow("Secondary Tileset", secondaryCombo);
|
||||
form.addRow("Layout Width", widthSpin);
|
||||
form.addRow("Layout Height", heightSpin);
|
||||
form.addRow("", errorMessageLabel);
|
||||
|
||||
connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){
|
||||
// verify some things
|
||||
bool issue = false;
|
||||
QString tryLayoutName = newNameEdit->text();
|
||||
// name not empty
|
||||
if (tryLayoutName.isEmpty()) {
|
||||
errorMessage = "Name cannot be empty";
|
||||
issue = true;
|
||||
}
|
||||
// unique layout name & id
|
||||
else if (this->editor->project->mapLayoutsTable.contains(newId->text())
|
||||
|| this->editor->project->layoutIdsToNames.find(tryLayoutName) != this->editor->project->layoutIdsToNames.end()) {
|
||||
errorMessage = "Layout Name / ID is not unique";
|
||||
issue = true;
|
||||
}
|
||||
// from id is existing value
|
||||
else if (useExistingCheck->isChecked()) {
|
||||
if (!this->editor->project->mapLayoutsTable.contains(useExistingCombo->currentText())) {
|
||||
errorMessage = "Existing layout ID is not valid";
|
||||
issue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (issue) {
|
||||
// show error
|
||||
errorMessageLabel->setText(errorMessage);
|
||||
errorMessageLabel->setVisible(true);
|
||||
}
|
||||
else {
|
||||
dialog.accept();
|
||||
}
|
||||
});
|
||||
|
||||
form.addRow(&newItemButtonBox);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
Layout::SimpleSettings layoutSettings;
|
||||
QString layoutName = newNameEdit->text();
|
||||
layoutSettings.name = layoutName;
|
||||
layoutSettings.id = Layout::layoutConstantFromName(layoutName.remove("_Layout"));
|
||||
if (useExistingCheck->isChecked()) {
|
||||
layoutSettings.from_id = useExistingCombo->currentText();
|
||||
} else {
|
||||
layoutSettings.width = widthSpin->value();
|
||||
layoutSettings.height = heightSpin->value();
|
||||
layoutSettings.tileset_primary_label = primaryCombo->currentText();
|
||||
layoutSettings.tileset_secondary_label = secondaryCombo->currentText();
|
||||
}
|
||||
Layout *newLayout = this->editor->project->createNewLayout(layoutSettings);
|
||||
QStandardItem *item = this->layoutTreeModel->insertLayoutItem(newLayout->id);
|
||||
setLayout(newLayout->id);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::mapListAddArea() {
|
||||
|
@ -1322,10 +1436,10 @@ void MainWindow::mapListAddItem() {
|
|||
this->mapListAddGroup();
|
||||
break;
|
||||
case 1:
|
||||
this->mapListAddLayout();
|
||||
this->mapListAddArea();
|
||||
break;
|
||||
case 2:
|
||||
this->mapListAddArea();
|
||||
this->mapListAddLayout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,6 +385,60 @@ QString Project::readMapLocation(QString map_name) {
|
|||
return ParseUtil::jsonToQString(mapObj["region_map_section"]);
|
||||
}
|
||||
|
||||
Layout *Project::createNewLayout(Layout::SimpleSettings &layoutSettings) {
|
||||
QString basePath = projectConfig.getFilePath(ProjectFilePath::data_layouts_folders);
|
||||
Layout *layout;
|
||||
|
||||
// Handle the case where we are copying from an existing layout first.
|
||||
if (!layoutSettings.from_id.isEmpty()) {
|
||||
// load from layout
|
||||
loadLayout(mapLayouts[layoutSettings.from_id]);
|
||||
|
||||
layout = mapLayouts[layoutSettings.from_id]->copy();
|
||||
layout->name = layoutSettings.name;
|
||||
layout->id = layoutSettings.id;
|
||||
layout->border_path = QString("%1%2/border.bin").arg(basePath, layoutSettings.name);
|
||||
layout->blockdata_path = QString("%1%2/map.bin").arg(basePath, layoutSettings.name);
|
||||
}
|
||||
else {
|
||||
layout = new Layout;
|
||||
|
||||
layout->name = layoutSettings.name;
|
||||
layout->id = layoutSettings.id;
|
||||
layout->width = layoutSettings.width;
|
||||
layout->height = layoutSettings.height;
|
||||
layout->border_width = DEFAULT_BORDER_WIDTH;
|
||||
layout->border_height = DEFAULT_BORDER_HEIGHT;
|
||||
layout->tileset_primary_label = layoutSettings.tileset_primary_label;
|
||||
layout->tileset_secondary_label = layoutSettings.tileset_secondary_label;
|
||||
layout->border_path = QString("%1%2/border.bin").arg(basePath, layoutSettings.name);
|
||||
layout->blockdata_path = QString("%1%2/map.bin").arg(basePath, layoutSettings.name);
|
||||
|
||||
setNewLayoutBlockdata(layout);
|
||||
setNewLayoutBorder(layout);
|
||||
}
|
||||
|
||||
// Create a new directory for the layout
|
||||
QString newLayoutDir = QString(root + "/%1%2").arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders), layout->name);
|
||||
if (!QDir::root().mkdir(newLayoutDir)) {
|
||||
logError(QString("Error: failed to create directory for new layout: '%1'").arg(newLayoutDir));
|
||||
delete layout;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mapLayouts.insert(layout->id, layout);
|
||||
mapLayoutsMaster.insert(layout->id, layout->copy());
|
||||
mapLayoutsTable.append(layout->id);
|
||||
mapLayoutsTableMaster.append(layout->id);
|
||||
layoutIdsToNames.insert(layout->id, layout->name);
|
||||
|
||||
saveLayout(layout);
|
||||
|
||||
this->loadLayout(layout);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
bool Project::loadLayout(Layout *layout) {
|
||||
// !TODO: make sure this doesn't break anything, maybe do something better. new layouts work too?
|
||||
if (!layout->loaded) {
|
||||
|
@ -1119,16 +1173,16 @@ bool Project::loadBlockdata(Layout *layout) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Project::setNewMapBlockdata(Map *map) {
|
||||
map->layout->blockdata.clear();
|
||||
int width = map->getWidth();
|
||||
int height = map->getHeight();
|
||||
void Project::setNewLayoutBlockdata(Layout *layout) {
|
||||
layout->blockdata.clear();
|
||||
int width = layout->getWidth();
|
||||
int height = layout->getHeight();
|
||||
Block block(projectConfig.getDefaultMetatileId(), projectConfig.getDefaultCollision(), projectConfig.getDefaultElevation());
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
map->layout->blockdata.append(block);
|
||||
layout->blockdata.append(block);
|
||||
}
|
||||
map->layout->lastCommitBlocks.blocks = map->layout->blockdata;
|
||||
map->layout->lastCommitBlocks.layoutDimensions = QSize(width, height);
|
||||
layout->lastCommitBlocks.blocks = layout->blockdata;
|
||||
layout->lastCommitBlocks.layoutDimensions = QSize(width, height);
|
||||
}
|
||||
|
||||
bool Project::loadLayoutBorder(Layout *layout) {
|
||||
|
@ -1147,27 +1201,27 @@ bool Project::loadLayoutBorder(Layout *layout) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Project::setNewMapBorder(Map *map) {
|
||||
map->layout->border.clear();
|
||||
int width = map->getBorderWidth();
|
||||
int height = map->getBorderHeight();
|
||||
void Project::setNewLayoutBorder(Layout *layout) {
|
||||
layout->border.clear();
|
||||
int width = layout->getBorderWidth();
|
||||
int height = layout->getBorderHeight();
|
||||
|
||||
const QList<uint16_t> configMetatileIds = projectConfig.getNewMapBorderMetatileIds();
|
||||
if (configMetatileIds.length() != width * height) {
|
||||
// Border size doesn't match the number of default border metatiles.
|
||||
// Fill the border with empty metatiles.
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
map->layout->border.append(0);
|
||||
layout->border.append(0);
|
||||
}
|
||||
} else {
|
||||
// Fill the border with the default metatiles from the config.
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
map->layout->border.append(configMetatileIds.at(i));
|
||||
layout->border.append(configMetatileIds.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
map->layout->lastCommitBlocks.border = map->layout->border;
|
||||
map->layout->lastCommitBlocks.borderDimensions = QSize(width, height);
|
||||
layout->lastCommitBlocks.border = layout->border;
|
||||
layout->lastCommitBlocks.borderDimensions = QSize(width, height);
|
||||
}
|
||||
|
||||
void Project::saveLayoutBorder(Layout *layout) {
|
||||
|
@ -1809,10 +1863,10 @@ Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool
|
|||
mapLayoutsTable.append(newMap->layoutId);
|
||||
layoutIdsToNames.insert(newMap->layout->id, newMap->layout->name);
|
||||
if (!importedMap) {
|
||||
setNewMapBlockdata(newMap);
|
||||
setNewLayoutBlockdata(newMap->layout);
|
||||
}
|
||||
if (newMap->layout->border.isEmpty()) {
|
||||
setNewMapBorder(newMap);
|
||||
setNewLayoutBorder(newMap->layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -535,6 +535,11 @@ QStandardItem *LayoutTreeModel::createMapItem(QString mapName) {
|
|||
return map;
|
||||
}
|
||||
|
||||
QStandardItem *LayoutTreeModel::insertLayoutItem(QString layoutId) {
|
||||
QStandardItem *layoutItem = this->createLayoutItem(layoutId);
|
||||
this->root->appendRow(layoutItem);
|
||||
}
|
||||
|
||||
QStandardItem *LayoutTreeModel::insertMapItem(QString mapName, QString layoutId) {
|
||||
QStandardItem *layout = nullptr;
|
||||
if (this->layoutItems.contains(layoutId)) {
|
||||
|
@ -591,6 +596,7 @@ QVariant LayoutTreeModel::data(const QModelIndex &index, int role) const {
|
|||
int col = index.column();
|
||||
|
||||
if (role == Qt::DecorationRole) {
|
||||
static QIcon mapGrayIcon = QIcon(QStringLiteral(":/icons/map_grayed.ico"));
|
||||
static QIcon mapIcon = QIcon(QStringLiteral(":/icons/map.ico"));
|
||||
static QIcon mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico"));
|
||||
static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico"));
|
||||
|
@ -607,6 +613,9 @@ QVariant LayoutTreeModel::data(const QModelIndex &index, int role) const {
|
|||
if (this->project->mapLayouts.value(layoutId)->hasUnsavedChanges()) {
|
||||
return mapEditedIcon;
|
||||
}
|
||||
else if (!this->project->mapLayouts[layoutId]->loaded) {
|
||||
return mapGrayIcon;
|
||||
}
|
||||
}
|
||||
return mapIcon;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue