Files
QtGameMaker/src/editor/dialogs/roompropertiesdialog.cpp
T
2025-12-20 20:24:39 +01:00

467 lines
16 KiB
C++

#include "roompropertiesdialog.h"
#include "ui_roompropertiesdialog.h"
#include <QSpinBox>
#include <QLabel>
#include <QToolButton>
#include <QMenu>
#include <QMessageBox>
#include <QDebug>
#include "projectcontainer.h"
#include "models/projecttreemodel.h"
#include "roomscene.h"
#include "editorguiutils.h"
#include "genericcodeeditordialog.h"
#include "mainwindow.h"
#include "editorsettings.h"
RoomPropertiesDialog::RoomPropertiesDialog(Room &room, ProjectTreeModel &projectModel, MainWindow &mainWindow) :
QDialog{&mainWindow},
m_ui{std::make_unique<Ui::RoomPropertiesDialog>()},
m_room{room},
m_projectModel{projectModel},
m_objects{m_room.objects},
m_scene{std::make_unique<RoomScene>(this)},
m_creationCode{m_room.creationCode},
m_spinBoxSnapX{new QSpinBox{this}},
m_spinBoxSnapY{new QSpinBox{this}},
m_menuObjects{new QMenu{this}},
m_labelX{new QLabel{tr("x: %0").arg(0)}},
m_labelY{new QLabel{tr("y: %0").arg(0)}}
{
m_ui->setupUi(this);
updateTitle();
m_ui->roomEditWidget->setObjects(&m_objects);
m_ui->roomEditWidget->setFixedWidth(m_room.width);
m_ui->roomEditWidget->setFixedHeight(m_room.height);
m_ui->roomEditWidget->setSnapX(m_room.snapX);
m_ui->roomEditWidget->setSnapY(m_room.snapY);
m_ui->roomEditWidget->setGridEnabled(m_room.gridEnabled);
m_ui->roomEditWidget->setIsometricGrid(m_room.isometricGrid);
m_ui->roomEditWidget->setProjectTreeModel(&m_projectModel);
m_ui->graphicsView->setScene(m_scene.get());
m_ui->graphicsView->setBackgroundBrush(makeGridBrush(16, 16, QPen{Qt::black}, Qt::white));
{
int index{11};
{
auto label = new QLabel{tr("Snap &X:"), this};
label->setBuddy(m_spinBoxSnapX);
m_ui->toolBar->insertWidget(m_ui->toolBar->actions().at(index++), label);
}
m_spinBoxSnapX->setValue(m_ui->roomEditWidget->snapX());
m_spinBoxSnapX->setMaximumWidth(50);
m_ui->toolBar->insertWidget(m_ui->toolBar->actions().at(index++), m_spinBoxSnapX);
{
auto label = new QLabel{tr("Snap &Y:"), this};
label->setBuddy(m_spinBoxSnapY);
m_ui->toolBar->insertWidget(m_ui->toolBar->actions().at(index++), label);
}
m_spinBoxSnapY->setValue(m_ui->roomEditWidget->snapY());
m_spinBoxSnapY->setMaximumWidth(50);
m_ui->toolBar->insertWidget(m_ui->toolBar->actions().at(index++), m_spinBoxSnapY);
}
m_ui->actionGridEnabled->setChecked(m_ui->roomEditWidget->gridEnabled());
m_ui->actionIsometricGrid->setChecked(m_ui->roomEditWidget->isometricGrid());
{
auto toolButton = new QToolButton{this};
toolButton->setText(tr("Show"));
toolButton->setIcon(QIcon{":/qtgameengine/icons/find.png"});
toolButton->setPopupMode(QToolButton::InstantPopup);
toolButton->addAction(m_ui->actionShowObjects);
toolButton->addAction(m_ui->actionShowTiles);
toolButton->addAction(m_ui->actionShowBackgrounds);
toolButton->addAction(m_ui->actionShowForegrounds);
toolButton->addAction(m_ui->actionShowViews);
m_ui->toolBar->addWidget(toolButton);
}
m_ui->toolButtonObject->setMenu(m_menuObjects);
m_ui->lineEditObject->setMenu(m_menuObjects);
m_ui->scrollAreaObject->setMenu(m_menuObjects);
m_ui->scrollAreaRoom->setBackgroundRole(QPalette::Dark);
m_labelX->setFrameStyle(QFrame::Sunken);
m_ui->statusbar->addWidget(m_labelX, 1);
m_labelY->setFrameStyle(QFrame::Sunken);
m_ui->statusbar->addWidget(m_labelY, 1);
{
auto frame = new QFrame{this};
frame->setFrameStyle(QFrame::Sunken);
m_ui->statusbar->addPermanentWidget(frame, 4);
}
m_ui->lineEditName->setText(m_room.name);
m_ui->lineEditCaption->setText(m_room.caption);
m_ui->spinBoxWidth->setValue(m_ui->roomEditWidget->width());
m_ui->spinBoxHeight->setValue(m_ui->roomEditWidget->height());
m_ui->spinBoxSpeed->setValue(m_room.speed);
m_ui->checkBoxPersistent->setChecked(m_room.persistent);
connect(&m_projectModel, &ProjectTreeModel::roomNameChanged,
this, &RoomPropertiesDialog::roomNameChanged);
connect(&m_projectModel, &ProjectTreeModel::spritePixmapsChanged,
this, &RoomPropertiesDialog::spritePixmapsChanged);
connect(&m_projectModel, &ProjectTreeModel::objectNameChanged,
this, &RoomPropertiesDialog::objectNameChanged);
connect(&m_projectModel, &ProjectTreeModel::objectAboutToBeRemoved,
this, &RoomPropertiesDialog::objectAboutToBeRemoved);
connect(&m_projectModel, &ProjectTreeModel::objectSpriteNameChanged,
this, &RoomPropertiesDialog::objectSpriteNameChanged);
connect(m_ui->actionUndo, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionClear, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionShift, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionSortX, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionSortY, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionLock, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_ui->actionUnlock, &QAction::triggered,
this, &RoomPropertiesDialog::undo);
connect(m_spinBoxSnapX, &QSpinBox::valueChanged,
m_ui->roomEditWidget, &RoomEditWidget::setSnapX);
connect(m_spinBoxSnapY, &QSpinBox::valueChanged,
m_ui->roomEditWidget, &RoomEditWidget::setSnapY);
connect(m_ui->actionGridEnabled, &QAction::toggled,
m_ui->roomEditWidget, &RoomEditWidget::setGridEnabled);
connect(m_ui->actionIsometricGrid, &QAction::toggled,
m_ui->roomEditWidget, &RoomEditWidget::setIsometricGrid);
connect(m_ui->spinBoxWidth, &QSpinBox::valueChanged,
m_ui->roomEditWidget, &RoomEditWidget::setFixedWidth);
connect(m_ui->spinBoxHeight, &QSpinBox::valueChanged,
m_ui->roomEditWidget, &RoomEditWidget::setFixedHeight);
connect(m_spinBoxSnapX, &QSpinBox::valueChanged,
this, &RoomPropertiesDialog::changed);
connect(m_spinBoxSnapY, &QSpinBox::valueChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->actionGridEnabled, &QAction::toggled,
this, &RoomPropertiesDialog::changed);
connect(m_ui->actionIsometricGrid, &QAction::toggled,
this, &RoomPropertiesDialog::changed);
connect(m_ui->lineEditName, &QLineEdit::textChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->lineEditCaption, &QLineEdit::textChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->spinBoxWidth, &QSpinBox::valueChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->spinBoxHeight, &QSpinBox::valueChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->spinBoxSpeed, &QSpinBox::valueChanged,
this, &RoomPropertiesDialog::changed);
connect(m_ui->checkBoxPersistent, &QCheckBox::toggled,
this, &RoomPropertiesDialog::changed);
connect(m_ui->pushButtonCreationCode, &QAbstractButton::clicked,
this, &RoomPropertiesDialog::editCreationCode);
connect(m_ui->roomEditWidget, &RoomEditWidget::snapXChanged,
m_spinBoxSnapX, &QSpinBox::setValue);
connect(m_ui->roomEditWidget, &RoomEditWidget::snapYChanged,
m_spinBoxSnapY, &QSpinBox::setValue);
connect(m_ui->roomEditWidget, &RoomEditWidget::gridEnabledChanged,
m_ui->actionGridEnabled, &QAction::setChecked);
connect(m_ui->roomEditWidget, &RoomEditWidget::isometricGridChanged,
m_ui->actionIsometricGrid, &QAction::setChecked);
connect(m_ui->roomEditWidget, &RoomEditWidget::cursorMoved,
this, &RoomPropertiesDialog::cursorMoved);
connect(m_ui->roomEditWidget, &RoomEditWidget::changed,
this, &RoomPropertiesDialog::changed);
connect(m_menuObjects, &QMenu::aboutToShow,
this, &RoomPropertiesDialog::objectsMenuAboutToShow);
if (!m_projectModel.project()->objects.empty())
setObject(m_projectModel.project()->objects.back());
connect(&mainWindow.settings(), &EditorSettings::advancedModeChanged,
this, &RoomPropertiesDialog::advancedModeChanged);
advancedModeChanged(mainWindow.settings().advancedMode());
}
RoomPropertiesDialog::~RoomPropertiesDialog() = default;
void RoomPropertiesDialog::accept()
{
if (!m_unsavedChanges)
{
QDialog::reject();
return;
}
if (m_room.name != m_ui->lineEditName->text())
{
if (!m_projectModel.rename<Room>(m_room, m_ui->lineEditName->text()))
{
QMessageBox::critical(this, tr("Renaming Room failed!"), tr("Renaming Room failed!"));
return;
}
}
m_room.caption = m_ui->lineEditCaption->text();
m_room.width = m_ui->spinBoxWidth->value();
m_room.height = m_ui->spinBoxHeight->value();
m_room.speed = m_ui->spinBoxSpeed->value();
m_room.persistent = m_ui->checkBoxPersistent->isChecked();
m_room.creationCode = m_creationCode;
m_room.snapX = m_spinBoxSnapX->value();
m_room.snapY = m_spinBoxSnapY->value();
m_room.gridEnabled = m_ui->actionGridEnabled->isChecked();
m_room.isometricGrid = m_ui->actionIsometricGrid->isChecked();
m_room.objects = m_objects;
QDialog::accept();
}
void RoomPropertiesDialog::reject()
{
if (!m_unsavedChanges)
{
QDialog::reject();
return;
}
const auto result = QMessageBox::warning(
this,
tr("The Room has been modified."),
tr("Do you want to save your changes?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
QMessageBox::Save
);
switch (result)
{
case QMessageBox::Save:
accept();
return;
case QMessageBox::Discard:
QDialog::reject();
return;
case QMessageBox::Cancel:
return;
default:
qWarning() << "unexpected dialog result" << result;
}
}
void RoomPropertiesDialog::undo()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::clearInstances()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::shiftInstances()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::sortInstancesX()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::sortInstancesY()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::lockInstances()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::unlockInstances()
{
QMessageBox::warning(this, tr("Not yet implemented"), tr("Not yet implemented"));
}
void RoomPropertiesDialog::editCreationCode()
{
GenericCodeEditorDialog dialog{tr("Room Creation Code"), this};
dialog.setScript(m_creationCode);
if (dialog.exec() == QDialog::Accepted)
{
m_creationCode = dialog.script();
changed();
}
}
void RoomPropertiesDialog::changed()
{
if (!m_unsavedChanges)
{
m_unsavedChanges = true;
updateTitle();
}
}
void RoomPropertiesDialog::roomNameChanged(const Room &room)
{
if (&room != &m_room)
return;
{
QSignalBlocker blocker{m_ui->lineEditName};
m_ui->lineEditName->setText(room.name);
}
updateTitle();
}
void RoomPropertiesDialog::spritePixmapsChanged(const Sprite &sprite)
{
if (!m_selectedObject)
return;
if (m_selectedObject->spriteName.isEmpty())
return;
if (m_selectedObject->spriteName != sprite.name)
return;
QPixmap pixmap;
if (!sprite.pixmaps.empty() && !sprite.pixmaps.front().isNull())
pixmap = sprite.pixmaps.front();
m_ui->labelObjectPreview->setPixmap(std::move(pixmap));
}
void RoomPropertiesDialog::objectNameChanged(const Object &object, const QString &oldName)
{
if (m_selectedObject && &object == m_selectedObject)
m_ui->lineEditObject->setText(object.name);
for (auto &obj : m_objects)
{
if (obj.objectName != oldName)
continue;
obj.objectName = object.name;
}
}
void RoomPropertiesDialog::objectAboutToBeRemoved(const Object &object)
{
if (m_selectedObject && &object == m_selectedObject)
{
m_selectedObject = nullptr;
m_ui->lineEditObject->clear();
m_ui->labelObjectPreview->setPixmap({});
m_ui->roomEditWidget->setSelectedObject(nullptr);
}
for (auto iter = std::begin(m_objects); iter != std::end(m_objects);)
if (iter->objectName == object.name)
iter = m_objects.erase(iter);
else
iter++;
}
void RoomPropertiesDialog::objectSpriteNameChanged(const Object &object)
{
if (!m_selectedObject)
return;
if (&object != m_selectedObject)
return;
QPixmap pixmap;
if (!object.spriteName.isEmpty())
{
const auto iter = std::find_if(std::cbegin(m_projectModel.project()->sprites), std::cend(m_projectModel.project()->sprites),
[&object](const auto &sprite){ return object.spriteName == sprite.name; });
if (iter == std::cend(m_projectModel.project()->sprites))
qWarning() << "invalid sprite" << object.spriteName;
else if (!iter->pixmaps.empty() && !iter->pixmaps.front().isNull())
pixmap = iter->pixmaps.front();
}
m_ui->labelObjectPreview->setPixmap(std::move(pixmap));
}
void RoomPropertiesDialog::objectsMenuAboutToShow()
{
m_menuObjects->clear();
for (const auto &object : m_projectModel.project()->objects)
{
QIcon icon;
if (!object.spriteName.isEmpty())
{
const auto iter = std::find_if(std::cbegin(m_projectModel.project()->sprites), std::cend(m_projectModel.project()->sprites),
[&object](const auto &sprite){ return object.spriteName == sprite.name; });
if (iter == std::cend(m_projectModel.project()->sprites))
qWarning() << "invalid sprite" << object.spriteName;
else if (!iter->pixmaps.empty() && !iter->pixmaps.front().isNull())
icon = iter->pixmaps.front();
}
m_menuObjects->addAction(icon, object.name, this,
[&object,this](){ setObject(object); });
}
}
void RoomPropertiesDialog::cursorMoved(const QPoint &point)
{
m_labelX->setText(tr("X: %0").arg(point.x()));
m_labelY->setText(tr("Y: %0").arg(point.y()));
}
void RoomPropertiesDialog::advancedModeChanged(bool advancedMode)
{
for (QWidget *widgets[] {
m_ui->checkBoxPersistent,
m_ui->pushButtonCreationCode
}; QWidget *widget : widgets)
widget->setVisible(advancedMode);
m_ui->tabWidget->setTabVisible(m_ui->tabWidget->indexOf(m_ui->tabTiles), advancedMode);
m_ui->tabWidget->setTabVisible(m_ui->tabWidget->indexOf(m_ui->tabViews), advancedMode);
}
void RoomPropertiesDialog::setObject(const Object &object)
{
m_selectedObject = &object;
QPixmap pixmap;
if (!object.spriteName.isEmpty())
{
const auto iter = std::find_if(std::cbegin(m_projectModel.project()->sprites), std::cend(m_projectModel.project()->sprites),
[&object](const auto &sprite){ return object.spriteName == sprite.name; });
if (iter == std::cend(m_projectModel.project()->sprites))
qWarning() << "invalid sprite" << object.spriteName;
else if (!iter->pixmaps.empty() && !iter->pixmaps.front().isNull())
pixmap = iter->pixmaps.front();
}
m_ui->labelObjectPreview->setPixmap(std::move(pixmap));
m_ui->lineEditObject->setText(object.name);
m_ui->roomEditWidget->setSelectedObject(&object);
}
void RoomPropertiesDialog::updateTitle()
{
setWindowTitle(tr("Room Properties: %0%1")
.arg(m_room.name)
.arg(m_unsavedChanges ? tr("*") : QString{})
);
}