Support custom event icons

This commit is contained in:
GriffinR 2023-12-05 02:01:44 -05:00
parent b88d62ecc1
commit 1b9b980121
10 changed files with 103 additions and 37 deletions

View file

@ -9,6 +9,8 @@
#include <QKeySequence> #include <QKeySequence>
#include <QMultiMap> #include <QMultiMap>
#include "events.h"
// In both versions the default new map border is a generic tree // In both versions the default new map border is a generic tree
#define DEFAULT_BORDER_RSE (QList<uint16_t>{0x1D4, 0x1D5, 0x1DC, 0x1DD}) #define DEFAULT_BORDER_RSE (QList<uint16_t>{0x1D4, 0x1D5, 0x1DC, 0x1DD})
#define DEFAULT_BORDER_FRLG (QList<uint16_t>{0x14, 0x15, 0x1C, 0x1D}) #define DEFAULT_BORDER_FRLG (QList<uint16_t>{0x14, 0x15, 0x1C, 0x1D})
@ -295,6 +297,11 @@ public:
void setMetatileLayerTypeMask(uint32_t mask); void setMetatileLayerTypeMask(uint32_t mask);
bool getMapAllowFlagsEnabled(); bool getMapAllowFlagsEnabled();
void setMapAllowFlagsEnabled(bool enabled); void setMapAllowFlagsEnabled(bool enabled);
void setEventIconPath(Event::Group group, const QString &path);
QString getEventIconPath(Event::Group group);
void setCollisionMapPath(const QString &path);
QString getCollisionMapPath();
protected: protected:
virtual QString getConfigFilepath() override; virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override; virtual void parseConfigKeyValue(QString key, QString value) override;
@ -332,6 +339,8 @@ private:
uint32_t metatileEncounterTypeMask; uint32_t metatileEncounterTypeMask;
uint32_t metatileLayerTypeMask; uint32_t metatileLayerTypeMask;
bool enableMapAllowFlags; bool enableMapAllowFlags;
QMap<Event::Group, QString> eventIconPaths;
QString collisionMapPath;
}; };
extern ProjectConfig projectConfig; extern ProjectConfig projectConfig;

View file

@ -111,6 +111,7 @@ public:
} }
} }
static QMap<Event::Group, const QPixmap*> icons;
// standard public methods // standard public methods
public: public:
@ -155,7 +156,7 @@ public:
const QMap<QString, QJsonValue> getCustomValues() { return this->customValues; } const QMap<QString, QJsonValue> getCustomValues() { return this->customValues; }
void setCustomValues(const QMap<QString, QJsonValue> newCustomValues) { this->customValues = newCustomValues; } void setCustomValues(const QMap<QString, QJsonValue> newCustomValues) { this->customValues = newCustomValues; }
virtual void loadPixmap(Project *project) = 0; virtual void loadPixmap(Project *project);
void setPixmap(QPixmap newPixmap) { this->pixmap = newPixmap; } void setPixmap(QPixmap newPixmap) { this->pixmap = newPixmap; }
QPixmap getPixmap() { return this->pixmap; } QPixmap getPixmap() { return this->pixmap; }
@ -177,6 +178,7 @@ public:
static QString eventGroupToString(Event::Group group); static QString eventGroupToString(Event::Group group);
static QString eventTypeToString(Event::Type type); static QString eventTypeToString(Event::Type type);
static Event::Type eventTypeFromString(QString type); static Event::Type eventTypeFromString(QString type);
static void initIcons();
// protected attributes // protected attributes
protected: protected:
@ -258,6 +260,8 @@ public:
void setFrameFromMovement(QString movement); void setFrameFromMovement(QString movement);
void setPixmapFromSpritesheet(QImage, int, int, bool); void setPixmapFromSpritesheet(QImage, int, int, bool);
static const QPixmap * defaultIcon;
protected: protected:
QString gfx; QString gfx;
@ -337,14 +341,14 @@ public:
virtual QSet<QString> getExpectedFields() override; virtual QSet<QString> getExpectedFields() override;
virtual void loadPixmap(Project *) override;
void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; } void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; }
QString getDestinationMap() { return this->destinationMap; } QString getDestinationMap() { return this->destinationMap; }
void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; }
QString getDestinationWarpID() { return this->destinationWarpID; } QString getDestinationWarpID() { return this->destinationWarpID; }
static const QPixmap * defaultIcon;
private: private:
QString destinationMap; QString destinationMap;
QString destinationWarpID; QString destinationWarpID;
@ -372,7 +376,7 @@ public:
virtual QSet<QString> getExpectedFields() override = 0; virtual QSet<QString> getExpectedFields() override = 0;
virtual void loadPixmap(Project *) override; static const QPixmap * defaultIcon;
}; };
@ -473,7 +477,7 @@ public:
virtual QSet<QString> getExpectedFields() override = 0; virtual QSet<QString> getExpectedFields() override = 0;
virtual void loadPixmap(Project *project) override; static const QPixmap * defaultIcon;
}; };
@ -614,8 +618,6 @@ public:
virtual QSet<QString> getExpectedFields() override { return QSet<QString>(); } virtual QSet<QString> getExpectedFields() override { return QSet<QString>(); }
virtual void loadPixmap(Project *project) override;
void setIndex(int newIndex) { this->index = newIndex; } void setIndex(int newIndex) { this->index = newIndex; }
int getIndex() { return this->index; } int getIndex() { return this->index; }
@ -631,6 +633,8 @@ public:
void setRespawnNPC(uint8_t newRespawnNPC) { this->respawnNPC = newRespawnNPC; } void setRespawnNPC(uint8_t newRespawnNPC) { this->respawnNPC = newRespawnNPC; }
uint8_t getRespawnNPC() { return this->respawnNPC; } uint8_t getRespawnNPC() { return this->respawnNPC; }
static const QPixmap * defaultIcon;
private: private:
int index = -1; int index = -1;
QString locationName; QString locationName;

View file

@ -86,8 +86,6 @@ public:
bool usingAsmTilesets; bool usingAsmTilesets;
QString importExportPath; QString importExportPath;
const QPixmap entitiesPixmap = QPixmap(":/images/Entities_16x16.png");
void set_root(QString); void set_root(QString);
void initSignals(); void initSignals();

View file

@ -6,7 +6,9 @@
class MovementPermissionsSelector: public SelectablePixmapItem { class MovementPermissionsSelector: public SelectablePixmapItem {
Q_OBJECT Q_OBJECT
public: public:
MovementPermissionsSelector(): SelectablePixmapItem(32, 32, 1, 1) { MovementPermissionsSelector(QPixmap basePixmap) :
SelectablePixmapItem(32, 32, 1, 1),
basePixmap(basePixmap) {
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
} }
void draw(); void draw();
@ -20,6 +22,7 @@ protected:
private: private:
void setSelectedMovementPermissions(QPointF); void setSelectedMovementPermissions(QPointF);
const QPixmap basePixmap;
signals: signals:
void hoveredMovementPermissionChanged(uint16_t, uint16_t); void hoveredMovementPermissionChanged(uint16_t, uint16_t);

View file

@ -684,6 +684,16 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
this->tilesetsHaveCallback = getConfigBool(key, value); this->tilesetsHaveCallback = getConfigBool(key, value);
} else if (key == "tilesets_have_is_compressed") { } else if (key == "tilesets_have_is_compressed") {
this->tilesetsHaveIsCompressed = getConfigBool(key, value); this->tilesetsHaveIsCompressed = getConfigBool(key, value);
} else if (key == "event_icon_path_object") {
this->eventIconPaths[Event::Group::Object] = value;
} else if (key == "event_icon_path_warp") {
this->eventIconPaths[Event::Group::Warp] = value;
} else if (key == "event_icon_path_coord") {
this->eventIconPaths[Event::Group::Coord] = value;
} else if (key == "event_icon_path_bg") {
this->eventIconPaths[Event::Group::Bg] = value;
} else if (key == "event_icon_path_heal") {
this->eventIconPaths[Event::Group::Heal] = value;
} else { } else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
} }
@ -751,6 +761,11 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
map.insert("metatile_encounter_type_mask", "0x" + QString::number(this->metatileEncounterTypeMask, 16).toUpper()); map.insert("metatile_encounter_type_mask", "0x" + QString::number(this->metatileEncounterTypeMask, 16).toUpper());
map.insert("metatile_layer_type_mask", "0x" + QString::number(this->metatileLayerTypeMask, 16).toUpper()); map.insert("metatile_layer_type_mask", "0x" + QString::number(this->metatileLayerTypeMask, 16).toUpper());
map.insert("enable_map_allow_flags", QString::number(this->enableMapAllowFlags)); map.insert("enable_map_allow_flags", QString::number(this->enableMapAllowFlags));
map.insert("event_icon_path_object", this->eventIconPaths[Event::Group::Object]);
map.insert("event_icon_path_warp", this->eventIconPaths[Event::Group::Warp]);
map.insert("event_icon_path_coord", this->eventIconPaths[Event::Group::Coord]);
map.insert("event_icon_path_bg", this->eventIconPaths[Event::Group::Bg]);
map.insert("event_icon_path_heal", this->eventIconPaths[Event::Group::Heal]);
return map; return map;
} }
@ -1091,6 +1106,24 @@ void ProjectConfig::setMapAllowFlagsEnabled(bool enabled) {
this->save(); this->save();
} }
// TODO: Expose to project settings editor
void ProjectConfig::setEventIconPath(Event::Group group, const QString &path) {
this->eventIconPaths[group] = path;
this->save();
}
QString ProjectConfig::getEventIconPath(Event::Group group) {
return this->eventIconPaths.value(group);
}
void ProjectConfig::setCollisionMapPath(const QString &path) {
this->collisionMapPath = path;
this->save();
}
QString ProjectConfig::getCollisionMapPath() {
return this->collisionMapPath;
}
UserConfig userConfig; UserConfig userConfig;

View file

@ -4,7 +4,7 @@
#include "project.h" #include "project.h"
#include "config.h" #include "config.h"
QMap<Event::Group, const QPixmap*> Event::icons;
Event::~Event() { Event::~Event() {
if (this->eventFrame) if (this->eventFrame)
@ -126,6 +126,45 @@ Event::Type Event::eventTypeFromString(QString type) {
} }
} }
void Event::loadPixmap(Project *) {
const QPixmap * pixmap = Event::icons.value(this->getEventGroup());
this->pixmap = pixmap ? *pixmap : QPixmap();
}
void Event::initIcons() {
qDeleteAll(icons);
icons.clear();
const int w = 16;
const int h = 16;
static const QPixmap defaultIcons = QPixmap(":/images/Entities_16x16.png");
// Custom event icons may be provided by the user.
const int numIcons = qMin(defaultIcons.width() / w, static_cast<int>(Event::Group::None));
for (int i = 0; i < numIcons; i++) {
Event::Group group = static_cast<Event::Group>(i);
QString customIconPath = projectConfig.getEventIconPath(group);
if (customIconPath.isEmpty()) {
// No custom icon specified, use the default icon.
icons[group] = new QPixmap(defaultIcons.copy(i * w, 0, w, h));
continue;
}
// Try to load custom icon
QFileInfo info(customIconPath);
if (info.isRelative()) {
customIconPath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + customIconPath);
}
const QPixmap customIcon = QPixmap(customIconPath);
if (customIcon.isNull()) {
// Custom icon failed to load, use the default icon.
icons[group] = new QPixmap(defaultIcons.copy(i * w, 0, w, h));
logError(QString("Failed to load custom event icon '%1', using default icon.").arg(customIconPath));
} else {
icons[group] = new QPixmap(customIcon);
}
}
}
Event *ObjectEvent::duplicate() { Event *ObjectEvent::duplicate() {
@ -243,7 +282,7 @@ void ObjectEvent::loadPixmap(Project *project) {
if (!eventGfx || eventGfx->spritesheet.isNull()) { if (!eventGfx || eventGfx->spritesheet.isNull()) {
// No sprite associated with this gfx constant. // No sprite associated with this gfx constant.
// Use default sprite instead. // Use default sprite instead.
this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16); Event::loadPixmap(project);
this->spriteWidth = 16; this->spriteWidth = 16;
this->spriteHeight = 16; this->spriteHeight = 16;
this->usingSprite = false; this->usingSprite = false;
@ -389,7 +428,7 @@ void CloneObjectEvent::loadPixmap(Project *project) {
if (!eventGfx || eventGfx->spritesheet.isNull()) { if (!eventGfx || eventGfx->spritesheet.isNull()) {
// No sprite associated with this gfx constant. // No sprite associated with this gfx constant.
// Use default sprite instead. // Use default sprite instead.
this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16); Event::loadPixmap(project);
this->spriteWidth = 16; this->spriteWidth = 16;
this->spriteHeight = 16; this->spriteHeight = 16;
this->usingSprite = false; this->usingSprite = false;
@ -478,17 +517,6 @@ QSet<QString> WarpEvent::getExpectedFields() {
return expectedFields; return expectedFields;
} }
void WarpEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(16, 0, 16, 16);
}
void CoordEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(32, 0, 16, 16);
}
Event *TriggerEvent::duplicate() { Event *TriggerEvent::duplicate() {
TriggerEvent *copy = new TriggerEvent(); TriggerEvent *copy = new TriggerEvent();
@ -632,12 +660,6 @@ QSet<QString> WeatherTriggerEvent::getExpectedFields() {
void BGEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(48, 0, 16, 16);
}
Event *SignEvent::duplicate() { Event *SignEvent::duplicate() {
SignEvent *copy = new SignEvent(); SignEvent *copy = new SignEvent();
@ -897,7 +919,3 @@ void HealLocationEvent::setDefaultValues(Project *) {
this->setRespawnNPC(1); this->setRespawnNPC(1);
} }
} }
void HealLocationEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(64, 0, 16, 16);
}

View file

@ -1484,7 +1484,7 @@ void Editor::displayMovementPermissionSelector() {
scene_collision_metatiles = new QGraphicsScene; scene_collision_metatiles = new QGraphicsScene;
if (!movement_permissions_selector_item) { if (!movement_permissions_selector_item) {
movement_permissions_selector_item = new MovementPermissionsSelector(); movement_permissions_selector_item = new MovementPermissionsSelector(QPixmap(":/images/collisions.png").scaled(32 * 2, 32 * 16)); // TODO: Don't assume default
connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionChanged, connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionChanged,
this, &Editor::onHoveredMovementPermissionChanged); this, &Editor::onHoveredMovementPermissionChanged);
connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionCleared, connect(movement_permissions_selector_item, &MovementPermissionsSelector::hoveredMovementPermissionCleared,

View file

@ -514,6 +514,7 @@ bool MainWindow::openProject(QString dir) {
this->setProjectSpecificUIVisibility(); this->setProjectSpecificUIVisibility();
this->newMapDefaultsSet = false; this->newMapDefaultsSet = false;
Event::initIcons();
Scripting::init(this); Scripting::init(this);
bool already_open = isProjectOpen() && (editor->project->root == dir); bool already_open = isProjectOpen() && (editor->project->root == dir);
if (!already_open) { if (!already_open) {

View file

@ -7,6 +7,7 @@ QImage getCollisionMetatileImage(Block block) {
return getCollisionMetatileImage(block.collision, block.elevation); return getCollisionMetatileImage(block.collision, block.elevation);
} }
// TODO:
QImage getCollisionMetatileImage(int collision, int elevation) { QImage getCollisionMetatileImage(int collision, int elevation) {
static const QImage collisionImage(":/images/collisions.png"); static const QImage collisionImage(":/images/collisions.png");
int x = (collision != 0) * 16; int x = (collision != 0) * 16;

View file

@ -2,8 +2,7 @@
#include <QPainter> #include <QPainter>
void MovementPermissionsSelector::draw() { void MovementPermissionsSelector::draw() {
QPixmap pixmap(":/images/collisions.png"); this->setPixmap(this->basePixmap);
this->setPixmap(pixmap.scaled(64, 512));
this->drawSelection(); this->drawSelection();
} }