diff --git a/QtGameMaker.pro b/QtGameMaker.pro index 7fef9e6..1184509 100644 --- a/QtGameMaker.pro +++ b/QtGameMaker.pro @@ -53,6 +53,7 @@ HEADERS += \ src/engine/vulkangamerenderer.h \ src/engine/vulkangamewindow.h \ src/futurecpp.h \ + src/imagehelpers.h \ src/projectcontainer.h \ src/editor/jshighlighter.h \ src/editor/mainwindow.h \ @@ -126,6 +127,7 @@ SOURCES += \ src/engine/glgamewindow.cpp \ src/engine/vulkangamerenderer.cpp \ src/engine/vulkangamewindow.cpp \ + src/imagehelpers.cpp \ src/main.cpp \ src/projectcontainer.cpp \ src/editor/jshighlighter.cpp \ diff --git a/src/editor/dialogs/editspritedialog.cpp b/src/editor/dialogs/editspritedialog.cpp index 4545e8a..a71dc4d 100644 --- a/src/editor/dialogs/editspritedialog.cpp +++ b/src/editor/dialogs/editspritedialog.cpp @@ -8,6 +8,7 @@ #include "models/spritesmodel.h" #include "createspritedialog.h" #include "imageeditordialog.h" +#include "imagehelpers.h" EditSpriteDialog::EditSpriteDialog(const std::vector &pixmaps, const QString &spriteName, QWidget *parent) : QDialog{parent}, @@ -34,8 +35,12 @@ EditSpriteDialog::EditSpriteDialog(const std::vector &pixmaps, const QS m_ui->listView->setModel(m_model.get()); connect(m_ui->actionNew, &QAction::triggered, this, &EditSpriteDialog::newSprite); + connect(m_ui->actionSaveAsPngFile, &QAction::triggered, this, &EditSpriteDialog::saveAsPng); connect(m_ui->listView, &QAbstractItemView::activated, this, &EditSpriteDialog::activated); + connect(m_ui->listView->selectionModel(), &QItemSelectionModel::currentChanged, + this, &EditSpriteDialog::currentChanged); + currentChanged(m_ui->listView->currentIndex()); } EditSpriteDialog::~EditSpriteDialog() = default; @@ -99,6 +104,28 @@ void EditSpriteDialog::newSprite() } } +void EditSpriteDialog::saveAsPng() +{ + auto index = m_ui->listView->currentIndex(); + if (!index.isValid()) + return; + + if (index.row() < 0 || (size_t)index.row() >= m_pixmaps.size()) + { + qWarning() << "invalid row" << index.row(); + return; + } + + const auto &pixmap = m_pixmaps[index.row()]; + if (pixmap.isNull()) + { + QMessageBox::warning(this, tr("Invalid sprite!"), tr("The sprite you tried to save is invalid!")); + return; + } + + saveImage(this, pixmap.toImage()); +} + void EditSpriteDialog::activated(const QModelIndex &index) { if (!index.isValid()) @@ -117,6 +144,11 @@ void EditSpriteDialog::activated(const QModelIndex &index) } } +void EditSpriteDialog::currentChanged(const QModelIndex &index) +{ + m_ui->actionSaveAsPngFile->setEnabled(index.isValid()); +} + void EditSpriteDialog::changed() { if (!m_unsavedChanges) diff --git a/src/editor/dialogs/editspritedialog.h b/src/editor/dialogs/editspritedialog.h index bf2428a..d1a7fe3 100644 --- a/src/editor/dialogs/editspritedialog.h +++ b/src/editor/dialogs/editspritedialog.h @@ -25,7 +25,10 @@ public: private slots: void newSprite(); + void saveAsPng(); + void activated(const QModelIndex &index); + void currentChanged(const QModelIndex &index); void changed(); diff --git a/src/editor/dialogs/imageeditordialog.cpp b/src/editor/dialogs/imageeditordialog.cpp index 412d763..fca81d1 100644 --- a/src/editor/dialogs/imageeditordialog.cpp +++ b/src/editor/dialogs/imageeditordialog.cpp @@ -7,6 +7,8 @@ #include #include +#include "imagehelpers.h" + ImageEditorDialog::ImageEditorDialog(const QPixmap &pixmap, const QString &title, QWidget *parent) : QDialog{parent}, m_ui{std::make_unique()}, @@ -29,6 +31,9 @@ ImageEditorDialog::ImageEditorDialog(const QPixmap &pixmap, const QString &title m_ui->scrollArea->setBackgroundRole(QPalette::Dark); + connect(m_ui->actionSaveAsPngFile, &QAction::triggered, + this, &ImageEditorDialog::saveAsPng); + connect(m_ui->pushButtonSelectFont, &QAbstractButton::pressed, this, &ImageEditorDialog::selectFont); @@ -136,6 +141,11 @@ QPixmap ImageEditorDialog::pixmap() const return m_ui->canvas->pixmap(); } +const QImage &ImageEditorDialog::image() const +{ + return m_ui->canvas->image(); +} + void ImageEditorDialog::accept() { // TODO @@ -173,6 +183,18 @@ void ImageEditorDialog::reject() } } +void ImageEditorDialog::saveAsPng() +{ + const auto &image = m_ui->canvas->image(); + if (image.isNull()) + { + QMessageBox::warning(this, tr("Invalid sprite!"), tr("The sprite you tried to save is invalid!")); + return; + } + + saveImage(this, image); +} + void ImageEditorDialog::changed() { if (!m_unsavedChanges) diff --git a/src/editor/dialogs/imageeditordialog.h b/src/editor/dialogs/imageeditordialog.h index 1e610f7..fa0d7a7 100644 --- a/src/editor/dialogs/imageeditordialog.h +++ b/src/editor/dialogs/imageeditordialog.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -9,6 +8,8 @@ #include "widgets/drawingcanvaswidget.h" class QLabel; +class QPixmap; +class QImage; namespace Ui { class ImageEditorDialog; } class ImageEditorDialog : public QDialog @@ -20,11 +21,13 @@ public: ~ImageEditorDialog(); QPixmap pixmap() const; + const QImage &image() const; void accept() override; void reject() override; private slots: + void saveAsPng(); void changed(); void selectFont(); void selectLeftButtonColor(); diff --git a/src/editor/dialogs/spritepropertiesdialog.cpp b/src/editor/dialogs/spritepropertiesdialog.cpp index 35fbccd..01f145d 100644 --- a/src/editor/dialogs/spritepropertiesdialog.cpp +++ b/src/editor/dialogs/spritepropertiesdialog.cpp @@ -11,6 +11,7 @@ #include "editspritedialog.h" #include "maskpropertiesdialog.h" #include "mainwindow.h" +#include "imagehelpers.h" SpritePropertiesDialog::SpritePropertiesDialog(Sprite &sprite, ProjectTreeModel &projectModel, MainWindow &mainWindow) : QDialog{&mainWindow}, @@ -157,22 +158,7 @@ void SpritePropertiesDialog::saveSprite() return; } - const auto path = QFileDialog::getSaveFileName(this, tr("Save a Sprite Image..."), m_sprite.name + ".png", - QStringLiteral("%0 (*.png);;%1 (*.bmp);;%2 (*.tiff);;%3 (*.jpg *.jpeg);;%4 (*)") - .arg(tr("PNG Files")) - .arg(tr("BMP Files")) - .arg(tr("TIFF Files")) - .arg(tr("JPEG Files")) - .arg(tr("All Files")) - ); - if (path.isEmpty()) - return; - - if (!m_pixmaps.front().save(path)) - { - QMessageBox::warning(this, tr("Could not save Sprite!"), tr("Could not save Sprite!")); - return; - } + saveImage(this, m_pixmaps.front().toImage()); } void SpritePropertiesDialog::editSprite() diff --git a/src/editor/widgets/drawingcanvaswidget.cpp b/src/editor/widgets/drawingcanvaswidget.cpp index 1b3bac9..5f84ca9 100644 --- a/src/editor/widgets/drawingcanvaswidget.cpp +++ b/src/editor/widgets/drawingcanvaswidget.cpp @@ -88,7 +88,10 @@ void DrawingCanvasWidget::mousePressEvent(QMouseEvent *event) { QWidget::mousePressEvent(event); - auto zoomdPos = event->pos() / m_zoom; + QPoint zoomdPos( + std::round(event->pos().x() / m_zoom), + std::round(event->pos().y() / m_zoom) + ); auto left = event->button() == Qt::LeftButton; switch (event->button()) @@ -160,7 +163,10 @@ void DrawingCanvasWidget::mouseMoveEvent(QMouseEvent *event) { QWidget::mouseMoveEvent(event); - auto zoomdPos = event->pos() / m_zoom; + QPoint zoomdPos( + std::round(event->pos().x() / m_zoom), + std::round(event->pos().y() / m_zoom) + ); emit cursorMoved(zoomdPos); if (m_currentlyDrawing) diff --git a/src/editor/widgets/drawingcanvaswidget.h b/src/editor/widgets/drawingcanvaswidget.h index 5bc6b30..689a5d6 100644 --- a/src/editor/widgets/drawingcanvaswidget.h +++ b/src/editor/widgets/drawingcanvaswidget.h @@ -37,6 +37,8 @@ public: Mode mode() const { return m_mode; } void setMode(Mode mode); + const QImage &image() const { return m_image; } + QPixmap pixmap() const; void setPixmap(const QPixmap &pixmap); diff --git a/src/imagehelpers.cpp b/src/imagehelpers.cpp new file mode 100644 index 0000000..429c5d5 --- /dev/null +++ b/src/imagehelpers.cpp @@ -0,0 +1,89 @@ +#include "imagehelpers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void saveImage(QWidget *parent, const QImage &image) +{ + QList formats = QImageWriter::supportedImageFormats(); + if (formats.contains("png")) + formats.removeAll("png"); + formats.prepend("png"); + + QString filterString; + QString allFormats; + QHash lookup; + for (const QByteArray &format : std::as_const(formats)) + { + auto text = QCoreApplication::translate("imagehelpers", "%1 format (*.%2)").arg(format.toUpper(), format); + lookup.insert(text, format); + + if (!filterString.isEmpty()) + filterString += ";;"; + filterString.append(text); + + if (!allFormats.isEmpty()) + allFormats += " "; + allFormats += "*."; + allFormats += format; + } + + allFormats = QCoreApplication::translate("imagehelpers", "All Supported Formats (%0)").arg(allFormats); + if (!filterString.isEmpty()) + filterString += ";;"; + filterString.append(allFormats); + + QString selectedFilter; + QString fileName = QFileDialog::getSaveFileName(parent, "Save Image", QString(), filterString, &selectedFilter); + if (fileName.isEmpty()) + return; + + QByteArray selectedFormat; + if (auto iter = lookup.constFind(selectedFilter); iter != std::cend(lookup)) + { + selectedFormat = *iter; + QString suffix = '.' + *iter; + if (!fileName.endsWith(suffix, Qt::CaseInsensitive)) + { + if (QMessageBox::warning(parent, + QCoreApplication::translate("imagehelpers", "Append file extension?"), + QCoreApplication::translate("imagehelpers", "It seems like you didnt append the expected file extension %0 at the end.\n\nDo you want to automatically append it before saving?").arg(suffix), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + { + fileName += suffix; + if (QFileInfo::exists(fileName)) + { + if (QMessageBox::warning(parent, + QCoreApplication::translate("imagehelpers", "Overwrite file?"), + QCoreApplication::translate("imagehelpers", "The file\n\n%0\n\nalready exists. Should it be overwritten?").arg(fileName), + QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok) + return; + } + } + } + } + else if (auto iter = std::find_if(std::cbegin(formats), std::cend(formats), + [&fileName](const QByteArray &format){ + return fileName.endsWith("." + format, Qt::CaseInsensitive); + }); iter != std::cend(formats)) + { + selectedFormat = *iter; + } + else + { + QMessageBox::warning(parent, QCoreApplication::translate("imagehelpers", "Unknown file format!"), QCoreApplication::translate("imagehelpers", "Unknown file format!")); + return; + } + + QImageWriter writer{fileName, selectedFormat}; + if (!writer.write(image)) + QMessageBox::warning(parent, QCoreApplication::translate("imagehelpers", "Error saving image!"), QCoreApplication::translate("imagehelpers", "Error saving image:\n\n%0").arg(writer.errorString())); +} diff --git a/src/imagehelpers.h b/src/imagehelpers.h new file mode 100644 index 0000000..4aa22bb --- /dev/null +++ b/src/imagehelpers.h @@ -0,0 +1,6 @@ +#pragma once + +class QWidget; +class QImage; + +void saveImage(QWidget *parent, const QImage &image);