diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84503118..9787f71d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp
### Fixed
- Fix rare crash while quitting Porymap.
+- Fix exported images on macOS using a different color space than in Porymap.
## [6.2.0] - 2025-08-08
### Added
diff --git a/forms/preferenceeditor.ui b/forms/preferenceeditor.ui
index 63017212..15584ae4 100644
--- a/forms/preferenceeditor.ui
+++ b/forms/preferenceeditor.ui
@@ -48,52 +48,74 @@
0
0
493
- 374
+ 408
-
-
-
- <html><head/><body><p>If checked, a prompt to reload your project will appear if relevant project files are edited</p></body></html>
-
-
- Monitor project files
-
-
-
- -
-
-
- <html><head/><body><p>If checked, Porymap will automatically open your most recently opened project on startup</p></body></html>
-
-
- Open recent project on launch
-
-
-
- -
-
-
- <html><head/><body><p>If checked, Porymap will automatically alert you on startup if a new release is available</p></body></html>
-
-
- Automatically check for updates
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Application Theme
-
-
+
+
-
+
+
+ <html><head/><body><p>If checked, Porymap will automatically alert you on startup if a new release is available</p></body></html>
+
+
+ Automatically check for updates
+
+
+
+ -
+
+
+ <html><head/><body><p>If checked, Porymap will automatically open your most recently opened project on startup</p></body></html>
+
+
+ Open recent project on launch
+
+
+
+ -
+
+
+ <html><head/><body><p>If checked, a prompt to reload your project will appear if relevant project files are edited</p></body></html>
+
+
+ Monitor project files
+
+
+
+ -
+
+
+ Application Theme
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ Image Export Color Space
+
+
+
+ -
+
+
+ <html><head/><body><p>The color space to use for exported images. If "---" is set, no color space will be used for the exported image. For details on each color space, see Qt's manual page for QColorSpace.</p></body></html>
+
+
+ false
+
+
+
+
-
@@ -483,6 +505,13 @@
+
+
+ NoScrollComboBox
+ QComboBox
+
+
+
diff --git a/include/config.h b/include/config.h
index 1f2a1a14..bfa990f0 100644
--- a/include/config.h
+++ b/include/config.h
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include "events.h"
@@ -145,6 +146,7 @@ public:
std::set statusBarLogTypes;
QFont applicationFont;
QFont mapListFont;
+ int imageExportColorSpaceId;
protected:
virtual void parseConfigKeyValue(QString key, QString value) override;
diff --git a/include/core/mapconnection.h b/include/core/mapconnection.h
index ba7c95a8..40713d3a 100644
--- a/include/core/mapconnection.h
+++ b/include/core/mapconnection.h
@@ -42,6 +42,7 @@ public:
MapConnection* createMirror();
QPixmap render() const;
+ QImage renderImage() const;
QPoint relativePixelPos(bool clipped = false) const;
static QPointer project;
diff --git a/include/core/utility.h b/include/core/utility.h
index 7270b552..ad8ce825 100644
--- a/include/core/utility.h
+++ b/include/core/utility.h
@@ -4,6 +4,7 @@
#include
#include
+#include
namespace Util {
void numericalModeSort(QStringList &list);
@@ -17,6 +18,7 @@ namespace Util {
void setErrorStylesheet(QLineEdit *lineEdit, bool isError);
QString toStylesheetString(const QFont &font);
void show(QWidget *w);
+ QColorSpace toColorSpace(int colorSpaceInt);
}
#endif // UTILITY_H
diff --git a/include/ui/mapimageexporter.h b/include/ui/mapimageexporter.h
index 789cf9b9..7bb9c027 100644
--- a/include/ui/mapimageexporter.h
+++ b/include/ui/mapimageexporter.h
@@ -58,6 +58,7 @@ private:
QBuffer *m_timelapseBuffer = nullptr;
QMovie *m_timelapseMovie = nullptr;
QGraphicsPixmapItem *m_preview = nullptr;
+ QImage m_previewImage;
ImageExporterSettings m_settings;
ImageExporterMode m_mode = ImageExporterMode::Normal;
@@ -77,15 +78,15 @@ private:
void setConnectionDirectionEnabled(const QString &dir, bool enable);
void saveImage();
QGifImage* createTimelapseGifImage(QProgressDialog *progress);
- QPixmap getStitchedImage(QProgressDialog *progress);
- QPixmap getFormattedMapPixmap();
+ QImage getStitchedImage(QProgressDialog *progress);
+ QImage getFormattedMapImage();
void paintBorder(QPainter *painter, Layout *layout);
void paintCollision(QPainter *painter, Layout *layout);
void paintConnections(QPainter *painter, const Map *map);
void paintEvents(QPainter *painter, const Map *map);
void paintGrid(QPainter *painter, const Layout *layout = nullptr);
QMargins getMargins(const Map *map);
- QPixmap getExpandedPixmap(const QPixmap &pixmap, const QSize &targetSize, const QColor &fillColor);
+ QImage getExpandedImage(const QImage &image, const QSize &targetSize, const QColor &fillColor);
bool currentHistoryAppliesToFrame(QUndoStack *historyStack);
protected:
diff --git a/include/ui/metatileimageexporter.h b/include/ui/metatileimageexporter.h
index 1d486bd4..20077d80 100644
--- a/include/ui/metatileimageexporter.h
+++ b/include/ui/metatileimageexporter.h
@@ -81,6 +81,7 @@ private:
CheckeredBgScene *m_scene = nullptr;
QGraphicsPixmapItem *m_preview = nullptr;
+ QImage m_previewImage;
bool m_previewUpdateQueued = false;
QList m_layerOrder;
ProjectConfig m_savedConfig;
diff --git a/include/ui/preferenceeditor.h b/include/ui/preferenceeditor.h
index 24b6253f..72b514c6 100644
--- a/include/ui/preferenceeditor.h
+++ b/include/ui/preferenceeditor.h
@@ -29,7 +29,6 @@ signals:
private:
Ui::PreferenceEditor *ui;
- NoScrollComboBox *themeSelector;
QFont applicationFont;
QFont mapListFont;
diff --git a/src/config.cpp b/src/config.cpp
index 4322e4cd..efeb2ce1 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -373,6 +373,16 @@ void PorymapConfig::reset() {
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
this->applicationFont = QFont();
this->mapListFont = PorymapConfig::defaultMapListFont();
+#ifdef Q_OS_MACOS
+ // Since the release of the Retina display, Apple products use the Display P3 color space by default.
+ // If we don't use this for exported images (which by default will either have no color space or the sRGB
+ // color space) then they may appear to have different colors than the same image displayed in Porymap.
+ this->imageExportColorSpaceId = static_cast(QColorSpace::DisplayP3);
+#else
+ // As of writing Qt has no way to get a reasonable color space from the user's environment,
+ // so we export images without one and let them handle it.
+ this->imageExportColorSpaceId = 0;
+#endif
}
void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
@@ -563,6 +573,8 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
} else if (key == "map_list_font") {
this->mapListFont = QFont();
this->mapListFont.fromString(value);
+ } else if (key == "image_export_color_space_id") {
+ this->imageExportColorSpaceId = getConfigInteger(key, value, 0, 8);
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
@@ -656,6 +668,7 @@ QMap PorymapConfig::getKeyValueMap() {
map.insert("status_bar_log_types", logTypesStrings.join(","));
map.insert("application_font", this->applicationFont.toString());
map.insert("map_list_font", this->mapListFont.toString());
+ map.insert("image_export_color_space_id", QString::number(this->imageExportColorSpaceId));
return map;
}
diff --git a/src/core/mapconnection.cpp b/src/core/mapconnection.cpp
index e1478fad..01a597b8 100644
--- a/src/core/mapconnection.cpp
+++ b/src/core/mapconnection.cpp
@@ -68,6 +68,12 @@ QPixmap MapConnection::render() const {
return map->renderConnection(m_direction, m_parentMap ? m_parentMap->layout() : nullptr);
}
+QImage MapConnection::renderImage() const {
+ render();
+ auto map = targetMap();
+ return (map && map->layout()) ? map->layout()->image : QImage();
+}
+
// Get the position of the target map relative to its parent map.
// For right/down connections this is offset by the dimensions of the parent map.
// For left/up connections this is offset by the dimensions of the target map.
diff --git a/src/core/utility.cpp b/src/core/utility.cpp
index 92cd1a4a..1c48f830 100644
--- a/src/core/utility.cpp
+++ b/src/core/utility.cpp
@@ -125,3 +125,23 @@ void Util::show(QWidget *w) {
w->activateWindow();
}
}
+
+// Safe conversion from an int representing a QColorSpace::NamedColorSpace to a QColorSpace.
+// This lets us use 0 to mean "no color space".
+QColorSpace Util::toColorSpace(int colorSpaceInt) {
+ QColorSpace colorSpace;
+
+ int min = static_cast(QColorSpace::SRgb);
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
+ // Qt 6.8.0 introduced additional color spaces
+ int max = static_cast(QColorSpace::Bt2100Hlg);
+#else
+ int max = static_cast(QColorSpace::ProPhotoRgb);
+#endif
+
+ if (colorSpaceInt >= min && colorSpaceInt <= max) {
+ return QColorSpace(static_cast(colorSpaceInt));
+ } else {
+ return QColorSpace();
+ }
+}
diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp
index 30c6ff72..91a6fb5a 100644
--- a/src/ui/mapimageexporter.cpp
+++ b/src/ui/mapimageexporter.cpp
@@ -185,9 +185,9 @@ void MapImageExporter::updateMapSelection() {
void MapImageExporter::saveImage() {
// If the preview is empty (because progress was canceled) or if updates were disabled
// then we should ensure the image in the preview is up-to-date before exporting.
- if (m_preview->pixmap().isNull() || m_settings.disablePreviewUpdates) {
+ if (m_previewImage.isNull() || m_settings.disablePreviewUpdates) {
updatePreview(true);
- if (m_preview->pixmap().isNull())
+ if (m_previewImage.isNull())
return; // Canceled
}
if (m_mode == ImageExporterMode::Timelapse && !m_timelapseGifImage) {
@@ -221,7 +221,7 @@ void MapImageExporter::saveImage() {
case ImageExporterMode::Normal:
case ImageExporterMode::Stitch:
// Normal and Stitch modes already have the image ready to go in the preview.
- m_preview->pixmap().save(filepath);
+ m_previewImage.save(filepath);
break;
case ImageExporterMode::Timelapse:
m_timelapseGifImage->save(filepath);
@@ -285,19 +285,19 @@ bool MapImageExporter::currentHistoryAppliesToFrame(QUndoStack *historyStack) {
}
}
-QPixmap MapImageExporter::getExpandedPixmap(const QPixmap &pixmap, const QSize &targetSize, const QColor &fillColor) {
- if (pixmap.width() >= targetSize.width() && pixmap.height() >= targetSize.height())
- return pixmap;
+QImage MapImageExporter::getExpandedImage(const QImage &image, const QSize &targetSize, const QColor &fillColor) {
+ if (image.width() >= targetSize.width() && image.height() >= targetSize.height())
+ return image;
- QPixmap resizedPixmap = QPixmap(targetSize);
- QPainter painter(&resizedPixmap);
- resizedPixmap.fill(fillColor);
+ QImage resizedImage(targetSize, QImage::Format_RGBA8888);
+ QPainter painter(&resizedImage);
+ resizedImage.fill(fillColor);
- // Center the old pixmap in the new resized one.
- int x = (targetSize.width() - pixmap.width()) / 2;
- int y = (targetSize.height() - pixmap.height()) / 2;
- painter.drawPixmap(x, y, pixmap.width(), pixmap.height(), pixmap);
- return resizedPixmap;
+ // Center the old image in the new resized one.
+ int x = (targetSize.width() - image.width()) / 2;
+ int y = (targetSize.height() - image.height()) / 2;
+ painter.drawImage(x, y, image);
+ return resizedImage;
}
struct TimelapseStep {
@@ -363,8 +363,7 @@ QGifImage* MapImageExporter::createTimelapseGifImage(QProgressDialog *progress)
while (step.historyStack->canRedo() && step.historyStack->index() < step.initialStackIndex && !progress->wasCanceled()) {
if (currentHistoryAppliesToFrame(step.historyStack) && --framesToSkip <= 0) {
// Render frame, increasing its size if necessary to match the canvas.
- QPixmap pixmap = getExpandedPixmap(getFormattedMapPixmap(), canvasSize, m_settings.fillColor);
- timelapseImg->addFrame(pixmap.toImage());
+ timelapseImg->addFrame(getExpandedImage(getFormattedMapImage(), canvasSize, m_settings.fillColor));
framesToSkip = m_settings.timelapseSkipAmount - 1;
}
step.historyStack->redo();
@@ -396,8 +395,7 @@ QGifImage* MapImageExporter::createTimelapseGifImage(QProgressDialog *progress)
// Final frame should always be the current state of the map.
if (timelapseImg) {
- QPixmap finalFrame = getExpandedPixmap(getFormattedMapPixmap(), canvasSize, m_settings.fillColor);
- timelapseImg->addFrame(finalFrame.toImage());
+ timelapseImg->addFrame(getExpandedImage(getFormattedMapImage(), canvasSize, m_settings.fillColor));
}
return timelapseImg;
}
@@ -408,7 +406,7 @@ struct StitchedMap {
Map* map;
};
-QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
+QImage MapImageExporter::getStitchedImage(QProgressDialog *progress) {
// Do a breadth-first search to gather a collection of
// all reachable maps with their relative offsets.
QSet visited;
@@ -419,7 +417,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
progress->setLabelText("Gathering stitched maps...");
while (!unvisited.isEmpty()) {
if (progress->wasCanceled()) {
- return QPixmap();
+ return QImage();
}
progress->setMaximum(visited.size() + unvisited.size());
progress->setValue(visited.size());
@@ -439,7 +437,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
}
}
if (stitchedMaps.isEmpty())
- return QPixmap();
+ return QImage();
progress->setMaximum(stitchedMaps.size());
int numDrawn = 0;
@@ -450,10 +448,10 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
dimensions |= (QRect(map.x, map.y, map.map->pixelWidth(), map.map->pixelHeight()) + getMargins(map.map));
}
- QPixmap stitchedPixmap(dimensions.width(), dimensions.height());
- stitchedPixmap.fill(m_settings.fillColor);
+ QImage stitchedImage(dimensions.width(), dimensions.height(), QImage::Format_RGBA8888);
+ stitchedImage.fill(m_settings.fillColor);
- QPainter painter(&stitchedPixmap);
+ QPainter painter(&stitchedImage);
painter.translate(-dimensions.left(), -dimensions.top());
// Borders can occlude neighboring maps, so we draw all the borders before drawing any maps.
@@ -469,7 +467,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
numDrawn = 0;
for (const StitchedMap &map : stitchedMaps) {
if (progress->wasCanceled()) {
- return QPixmap();
+ return QImage();
}
painter.translate(map.x, map.y);
paintBorder(&painter, map.map->layout());
@@ -485,10 +483,11 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
numDrawn = 0;
for (const StitchedMap &map : stitchedMaps) {
if (progress->wasCanceled()) {
- return QPixmap();
+ return QImage();
}
+ map.map->layout()->render(true);
painter.translate(map.x, map.y);
- painter.drawPixmap(0, 0, map.map->layout()->render(true));
+ painter.drawImage(0, 0, map.map->layout()->image);
paintCollision(&painter, map.map->layout());
painter.translate(-map.x, -map.y);
@@ -504,7 +503,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
numDrawn = 0;
for (const StitchedMap &map : stitchedMaps) {
if (progress->wasCanceled()) {
- return QPixmap();
+ return QImage();
}
painter.translate(map.x, map.y);
paintEvents(&painter, map.map);
@@ -515,7 +514,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
}
}
- return stitchedPixmap;
+ return stitchedImage;
}
void MapImageExporter::updatePreview(bool forceUpdate) {
@@ -528,18 +527,17 @@ void MapImageExporter::updatePreview(bool forceUpdate) {
progress.setModal(true);
progress.setMinimumDuration(1000);
- QPixmap previewPixmap;
if (m_mode == ImageExporterMode::Normal) {
- previewPixmap = getFormattedMapPixmap();
+ m_previewImage = getFormattedMapImage();
} else if (m_mode == ImageExporterMode::Stitch) {
- previewPixmap = getStitchedImage(&progress);
+ m_previewImage = getStitchedImage(&progress);
} else if (m_mode == ImageExporterMode::Timelapse) {
if (m_timelapseMovie)
m_timelapseMovie->stop();
m_timelapseGifImage = createTimelapseGifImage(&progress);
if (!m_timelapseGifImage) {
- previewPixmap = QPixmap();
+ m_previewImage = QImage();
} else {
// We want to convert the QGifImage data into a QMovie for the preview display.
// Both support input/output with a QIODevice, so we use a QBuffer to translate the data.
@@ -556,12 +554,15 @@ void MapImageExporter::updatePreview(bool forceUpdate) {
m_preview->setPixmap(m_timelapseMovie->currentPixmap());
});
m_timelapseMovie->start();
- previewPixmap = m_timelapseMovie->currentPixmap();
+ m_previewImage = m_timelapseMovie->currentImage();
}
+ } else {
+ m_previewImage = QImage();
}
progress.close();
- m_preview->setPixmap(previewPixmap);
+ m_previewImage.setColorSpace(Util::toColorSpace(porymapConfig.imageExportColorSpaceId));
+ m_preview->setPixmap(QPixmap::fromImage(m_previewImage));
m_scene->setSceneRect(m_scene->itemsBoundingRect());
scalePreview();
}
@@ -572,23 +573,24 @@ void MapImageExporter::scalePreview() {
ui->graphicsView_Preview->fitInView(m_preview, Qt::KeepAspectRatioByExpanding);
}
-QPixmap MapImageExporter::getFormattedMapPixmap() {
+QImage MapImageExporter::getFormattedMapImage() {
if (!m_layout)
- return QPixmap();
+ return QImage();
m_layout->render(true);
- // Create pixmap large enough to contain the map and the marginal elements (the border, grid, etc.)
+ // Create image large enough to contain the map and the marginal elements (the border, grid, etc.)
QMargins margins = getMargins(m_map);
- QPixmap pixmap = QPixmap(m_layout->pixmap.width() + margins.left() + margins.right(),
- m_layout->pixmap.height() + margins.top() + margins.bottom());
- pixmap.fill(m_settings.fillColor);
+ QImage image(m_layout->image.width() + margins.left() + margins.right(),
+ m_layout->image.height() + margins.top() + margins.bottom(),
+ QImage::Format_RGBA8888);
+ image.fill(m_settings.fillColor);
- QPainter painter(&pixmap);
+ QPainter painter(&image);
painter.translate(margins.left(), margins.top());
paintBorder(&painter, m_layout);
- painter.drawPixmap(0, 0, m_layout->pixmap);
+ painter.drawImage(0, 0, m_layout->image);
paintCollision(&painter, m_layout);
if (m_map) {
paintConnections(&painter, m_map);
@@ -596,7 +598,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap() {
}
paintGrid(&painter, m_layout);
- return pixmap;
+ return image;
}
QMargins MapImageExporter::getMargins(const Map *map) {
@@ -630,9 +632,11 @@ void MapImageExporter::paintCollision(QPainter *painter, Layout *layout) {
if (!m_settings.showCollision)
return;
+ layout->renderCollision(true);
+
auto savedOpacity = painter->opacity();
painter->setOpacity(static_cast(porymapConfig.collisionOpacity) / 100);
- painter->drawPixmap(0, 0, layout->renderCollision(true));
+ painter->drawImage(0, 0, layout->collision_image);
painter->setOpacity(savedOpacity);
}
@@ -652,7 +656,7 @@ void MapImageExporter::paintBorder(QPainter *painter, Layout *layout) {
// Skip border painting if it would be fully covered by the rest of the map
if (layout->isWithinBounds(QRect(x, y, layout->getBorderWidth(), layout->getBorderHeight())))
continue;
- painter->drawPixmap(x * Metatile::pixelWidth(), y * Metatile::pixelHeight(), layout->border_pixmap);
+ painter->drawImage(x * Metatile::pixelWidth(), y * Metatile::pixelHeight(), layout->border_image);
}
painter->restore();
@@ -665,7 +669,7 @@ void MapImageExporter::paintConnections(QPainter *painter, const Map *map) {
for (const auto &connection : map->getConnections()) {
if (!m_settings.showConnections.contains(connection->direction()))
continue;
- painter->drawImage(connection->relativePixelPos(true), connection->render().toImage());
+ painter->drawImage(connection->relativePixelPos(true), connection->renderImage());
}
}
diff --git a/src/ui/metatileimageexporter.cpp b/src/ui/metatileimageexporter.cpp
index 51b953df..f7e99fa0 100644
--- a/src/ui/metatileimageexporter.cpp
+++ b/src/ui/metatileimageexporter.cpp
@@ -185,7 +185,7 @@ void MetatileImageExporter::reset() {
QImage MetatileImageExporter::getImage() {
tryUpdatePreview();
- return m_preview->pixmap().toImage();
+ return m_previewImage;
}
bool MetatileImageExporter::saveImage(QString filepath) {
@@ -197,7 +197,7 @@ bool MetatileImageExporter::saveImage(QString filepath) {
return false;
}
}
- return m_preview->pixmap().save(filepath);
+ return m_previewImage.save(filepath);
}
QString MetatileImageExporter::getDefaultFileName() const {
@@ -244,7 +244,7 @@ void MetatileImageExporter::queuePreviewUpdate() {
// For updating only when a change has been recorded.
// Useful for something that might happen often, like an input widget losing focus.
void MetatileImageExporter::tryUpdatePreview() {
- if (m_preview->pixmap().isNull() || m_previewUpdateQueued) {
+ if (m_previewImage.isNull() || m_previewUpdateQueued) {
updatePreview();
}
}
@@ -261,15 +261,14 @@ void MetatileImageExporter::updatePreview() {
}
}
- QImage previewImage;
if (ui->checkBox_PrimaryTileset->isChecked() && ui->checkBox_SecondaryTileset->isChecked()) {
// Special behavior to combine the two tilesets while skipping the unused region between tilesets.
- previewImage = getMetatileSheetImage(m_primaryTileset,
+ m_previewImage = getMetatileSheetImage(m_primaryTileset,
m_secondaryTileset,
ui->spinBox_WidthMetatiles->value(),
m_layerOrder);
} else {
- previewImage = getMetatileSheetImage(m_primaryTileset,
+ m_previewImage = getMetatileSheetImage(m_primaryTileset,
m_secondaryTileset,
ui->spinBox_MetatileStart->value(),
ui->spinBox_MetatileEnd->value(),
@@ -277,7 +276,8 @@ void MetatileImageExporter::updatePreview() {
m_layerOrder);
}
- m_preview->setPixmap(QPixmap::fromImage(previewImage));
+ m_previewImage.setColorSpace(Util::toColorSpace(porymapConfig.imageExportColorSpaceId));
+ m_preview->setPixmap(QPixmap::fromImage(m_previewImage));
m_scene->setSceneRect(m_scene->itemsBoundingRect());
m_previewUpdateQueued = false;
diff --git a/src/ui/preferenceeditor.cpp b/src/ui/preferenceeditor.cpp
index 5765ba01..326197e8 100644
--- a/src/ui/preferenceeditor.cpp
+++ b/src/ui/preferenceeditor.cpp
@@ -6,23 +6,20 @@
#include
#include
#include
-#include
#include
#include
PreferenceEditor::PreferenceEditor(QWidget *parent) :
QMainWindow(parent),
- ui(new Ui::PreferenceEditor),
- themeSelector(nullptr)
+ ui(new Ui::PreferenceEditor)
{
ui->setupUi(this);
- auto *formLayout = new QFormLayout(ui->groupBox_Themes);
- themeSelector = new NoScrollComboBox(ui->groupBox_Themes);
- themeSelector->setEditable(false);
- themeSelector->setMinimumContentsLength(0);
- formLayout->addRow("Themes", themeSelector);
setAttribute(Qt::WA_DeleteOnClose);
+
+ ui->comboBox_ColorSpace->setMinimumContentsLength(0);
+ ui->comboBox_ApplicationTheme->setMinimumContentsLength(0);
+
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &PreferenceEditor::dialogButtonClicked);
connect(ui->pushButton_CustomizeApplicationFont, &QPushButton::clicked, [this] {
@@ -59,16 +56,35 @@ void PreferenceEditor::initFields() {
themes.append(themeName);
}
}
- themeSelector->addItems(themes);
+ ui->comboBox_ApplicationTheme->addItems(themes);
+
+ static const QMap colorSpaces = {
+ {"---", 0},
+ {"sRGB", QColorSpace::SRgb},
+ {"sRGB Linear", QColorSpace::SRgbLinear},
+ {"Adobe RGB", QColorSpace::AdobeRgb},
+ {"Display P3", QColorSpace::DisplayP3},
+ {"ProPhoto RGB", QColorSpace::ProPhotoRgb},
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
+ // Qt 6.8.0 introduced additional color spaces
+ {"BT.2020", QColorSpace::Bt2020},
+ {"BT.2100 (PQ)", QColorSpace::Bt2100Pq},
+ {"BT.2100 (HLG)", QColorSpace::Bt2100Hlg},
+#endif
+ };
+ for (auto it = colorSpaces.constBegin(); it != colorSpaces.constEnd(); it++) {
+ ui->comboBox_ColorSpace->addItem(it.key(), it.value());
+ }
}
void PreferenceEditor::updateFields() {
- themeSelector->setTextItem(porymapConfig.theme);
+ ui->comboBox_ApplicationTheme->setTextItem(porymapConfig.theme);
if (porymapConfig.eventSelectionShapeMode == QGraphicsPixmapItem::MaskShape) {
ui->radioButton_OnSprite->setChecked(true);
} else if (porymapConfig.eventSelectionShapeMode == QGraphicsPixmapItem::BoundingRectShape) {
ui->radioButton_WithinRect->setChecked(true);
}
+ ui->comboBox_ColorSpace->setNumberItem(porymapConfig.imageExportColorSpaceId);
ui->lineEdit_TextEditorOpenFolder->setText(porymapConfig.textEditorOpenFolder);
ui->lineEdit_TextEditorGotoLine->setText(porymapConfig.textEditorGotoLine);
ui->checkBox_MonitorProjectFiles->setChecked(porymapConfig.monitorFiles);
@@ -97,8 +113,8 @@ void PreferenceEditor::saveFields() {
bool needsProjectReload = false;
bool changedTheme = false;
- if (themeSelector->currentText() != porymapConfig.theme) {
- porymapConfig.theme = themeSelector->currentText();
+ if (ui->comboBox_ApplicationTheme->currentText() != porymapConfig.theme) {
+ porymapConfig.theme = ui->comboBox_ApplicationTheme->currentText();
changedTheme = true;
}
@@ -113,6 +129,7 @@ void PreferenceEditor::saveFields() {
emit scriptSettingsChanged(scriptAutocompleteMode);
}
+ porymapConfig.imageExportColorSpaceId = ui->comboBox_ColorSpace->currentData().toInt();
porymapConfig.eventSelectionShapeMode = ui->radioButton_OnSprite->isChecked() ? QGraphicsPixmapItem::MaskShape : QGraphicsPixmapItem::BoundingRectShape;
porymapConfig.textEditorOpenFolder = ui->lineEdit_TextEditorOpenFolder->text();
porymapConfig.textEditorGotoLine = ui->lineEdit_TextEditorGotoLine->text();