pull upstream changes

merge branch 'huderlem/master' into 'garakmon/master'
This commit is contained in:
garak 2018-10-03 10:48:27 -04:00 committed by GitHub
commit 52d612c333
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
100 changed files with 13906 additions and 9977 deletions

437
editor.h
View file

@ -1,437 +0,0 @@
#ifndef EDITOR_H
#define EDITOR_H
#include <QGraphicsScene>
#include <QGraphicsItemGroup>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsItemAnimation>
#include <QComboBox>
#include <QCheckBox>
#include <QCursor>
#include "project.h"
#include "ui_mainwindow.h"
class DraggablePixmapItem;
class MapPixmapItem;
class CollisionPixmapItem;
class ConnectionPixmapItem;
class MetatilesPixmapItem;
class BorderMetatilesPixmapItem;
class CurrentSelectedMetatilesPixmapItem;
class MovementPermissionsPixmapItem;
#define SWAP(a, b) do { if (a != b) { a ^= b; b ^= a; a ^= b; } } while (0)
class Editor : public QObject
{
Q_OBJECT
public:
Editor(Ui::MainWindow* ui);
public:
Ui::MainWindow* ui;
QObject *parent = nullptr;
Project *project = nullptr;
Map *map = nullptr;
void saveProject();
void save();
void undo();
void redo();
void setMap(QString map_name);
void updateCurrentMetatilesSelection();
void displayMap();
void displayMetatiles();
void displayBorderMetatiles();
void displayCurrentMetatilesSelection();
void redrawCurrentMetatilesSelection();
void displayCollisionMetatiles();
void displayElevationMetatiles();
void displayMapEvents();
void displayMapConnections();
void displayMapBorder();
void displayMapGrid();
void setEditingMap();
void setEditingCollision();
void setEditingObjects();
void setEditingConnections();
void setCurrentConnectionDirection(QString curDirection);
void updateCurrentConnectionDirection(QString curDirection);
void setConnectionsVisibility(bool visible);
void updateConnectionOffset(int offset);
void setConnectionMap(QString mapName);
void addNewConnection();
void removeCurrentConnection();
void updateDiveMap(QString mapName);
void updateEmergeMap(QString mapName);
void setSelectedConnectionFromMap(QString mapName);
void updatePrimaryTileset(QString tilesetLabel);
void updateSecondaryTileset(QString tilesetLabel);
void toggleBorderVisibility(bool visible);
DraggablePixmapItem *addMapEvent(Event *event);
void selectMapEvent(DraggablePixmapItem *object);
void selectMapEvent(DraggablePixmapItem *object, bool toggle);
DraggablePixmapItem *addNewEvent(QString event_type);
Event* createNewEvent(QString event_type);
void deleteEvent(Event *);
void updateSelectedEvents();
void redrawObject(DraggablePixmapItem *item);
QList<DraggablePixmapItem *> *getObjects();
QGraphicsScene *scene = nullptr;
QGraphicsPixmapItem *current_view = nullptr;
MapPixmapItem *map_item = nullptr;
ConnectionPixmapItem* selected_connection_item = nullptr;
QList<QGraphicsPixmapItem*> connection_items;
QList<ConnectionPixmapItem*> connection_edit_items;
CollisionPixmapItem *collision_item = nullptr;
QGraphicsItemGroup *events_group = nullptr;
QList<QGraphicsPixmapItem*> borderItems;
QList<QGraphicsLineItem*> gridLines;
QGraphicsScene *scene_metatiles = nullptr;
QGraphicsScene *scene_current_metatile_selection = nullptr;
QGraphicsScene *scene_selected_border_metatiles = nullptr;
QGraphicsScene *scene_collision_metatiles = nullptr;
QGraphicsScene *scene_elevation_metatiles = nullptr;
MetatilesPixmapItem *metatiles_item = nullptr;
BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr;
CurrentSelectedMetatilesPixmapItem *scene_current_metatile_selection_item = nullptr;
MovementPermissionsPixmapItem *collision_metatiles_item = nullptr;
QList<DraggablePixmapItem*> *events = nullptr;
QList<DraggablePixmapItem*> *selected_events = nullptr;
bool lastSelectedMetatilesFromMap = false;
int copiedMetatileSelectionWidth = 0;
int copiedMetatileSelectionHeight = 0;
QList<uint16_t> *copiedMetatileSelection = new QList<uint16_t>;
QString map_edit_mode;
QString prev_edit_mode;
QCursor cursor;
void objectsView_onMousePress(QMouseEvent *event);
void objectsView_onMouseMove(QMouseEvent *event);
void objectsView_onMouseRelease(QMouseEvent *event);
private:
void setConnectionItemsVisible(bool);
void setBorderItemsVisible(bool, qreal = 1);
void setConnectionEditControlValues(Connection*);
void setConnectionEditControlsEnabled(bool);
void createConnectionItem(Connection* connection, bool hide);
void populateConnectionMapPickers();
void setDiveEmergeControls();
void updateDiveEmergeMap(QString mapName, QString direction);
void onConnectionOffsetChanged(int newOffset);
void removeMirroredConnection(Connection*);
void updateMirroredConnectionOffset(Connection*);
void updateMirroredConnectionDirection(Connection*, QString);
void updateMirroredConnectionMap(Connection*, QString);
void updateMirroredConnection(Connection*, QString, QString, bool isDelete = false);
Event* createNewObjectEvent();
Event* createNewWarpEvent();
Event* createNewHealLocationEvent();
Event* createNewCoordScriptEvent();
Event* createNewCoordWeatherEvent();
Event* createNewSignEvent();
Event* createNewHiddenItemEvent();
Event* createNewSecretBaseEvent();
private slots:
void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item);
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
void onConnectionMoved(Connection*);
void onConnectionItemSelected(ConnectionPixmapItem* connectionItem);
void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
void onConnectionDirectionChanged(QString newDirection);
void onBorderMetatilesChanged();
signals:
void objectsChanged();
void selectedObjectsChanged();
void loadMapRequested(QString, QString);
void tilesetChanged(QString);
void warpEventDoubleClicked(QString mapName, QString warpNum);
void currentMetatilesSelectionChanged();
};
class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
}
Editor *editor = nullptr;
Event *event = nullptr;
QGraphicsItemAnimation *pos_anim = nullptr;
DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) {
event = event_;
editor = editor_;
updatePosition();
}
bool active;
int last_x;
int last_y;
void updatePosition() {
int x = event->getPixelX();
int y = event->getPixelY();
setX(x);
setY(y);
setZValue(event->y());
}
void move(int x, int y);
void emitPositionChanged() {
emit xChanged(event->x());
emit yChanged(event->y());
emit elevationChanged(event->elevation());
}
void updatePixmap() {
QList<Event*> objects;
objects.append(event);
event->pixmap = QPixmap();
editor->project->loadEventPixmaps(objects);
this->updatePosition();
editor->redrawObject(this);
emit spriteChanged(event->pixmap);
}
void bind(QComboBox *combo, QString key) {
connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
this, [this, key](QString value){
this->event->put(key, value);
});
connect(this, &DraggablePixmapItem::onPropertyChanged,
this, [combo, key](QString key2, QString value){
if (key2 == key) {
combo->addItem(value);
combo->setCurrentText(value);
}
});
}
signals:
void positionChanged(Event *event);
void xChanged(int);
void yChanged(int);
void elevationChanged(int);
void spriteChanged(QPixmap pixmap);
void onPropertyChanged(QString key, QString value);
public slots:
void set_x(const QString &text) {
event->put("x", text);
updatePosition();
}
void set_y(const QString &text) {
event->put("y", text);
updatePosition();
}
void set_elevation(const QString &text) {
event->put("elevation", text);
updatePosition();
}
void set_sprite(const QString &text) {
event->put("sprite", text);
updatePixmap();
}
void set_script(const QString &text) {
event->put("script_label", text);
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
};
class EventGroup : public QGraphicsItemGroup {
};
class MapPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
MapPixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
}
Map *map = nullptr;
Editor *editor = nullptr;
MapPixmapItem(Map *map_, Editor *editor_) {
map = map_;
editor = editor_;
setAcceptHoverEvents(true);
}
bool active;
bool right_click;
QPoint selection_origin;
QList<QPoint> selection;
virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*);
void _floodFill(int x, int y);
void _floodFillSmartPath(int initialX, int initialY);
virtual void pick(QGraphicsSceneMouseEvent*);
virtual void select(QGraphicsSceneMouseEvent*);
virtual void shift(QGraphicsSceneMouseEvent*);
virtual void draw(bool ignoreCache = false);
void updateMetatileSelection(QGraphicsSceneMouseEvent *event);
private:
void updateCurHoveredTile(QPointF pos);
void paintNormal(int x, int y);
void paintSmartPath(int x, int y);
static QList<int> smartPathTable;
signals:
void mouseEvent(QGraphicsSceneMouseEvent *, MapPixmapItem *);
protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
};
class CollisionPixmapItem : public MapPixmapItem {
Q_OBJECT
public:
CollisionPixmapItem(QPixmap pixmap): MapPixmapItem(pixmap) {
}
CollisionPixmapItem(Map *map_, Editor *editor_): MapPixmapItem(map_, editor_) {
}
void updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event);
virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*);
virtual void pick(QGraphicsSceneMouseEvent*);
virtual void draw(bool ignoreCache = false);
signals:
void mouseEvent(QGraphicsSceneMouseEvent *, CollisionPixmapItem *);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
};
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
ConnectionPixmapItem(QPixmap pixmap, Connection* connection, int x, int y, int baseMapWidth, int baseMapHeight): QGraphicsPixmapItem(pixmap) {
this->basePixmap = pixmap;
this->connection = connection;
setFlag(ItemIsMovable);
setFlag(ItemSendsGeometryChanges);
this->initialX = x;
this->initialY = y;
this->initialOffset = connection->offset.toInt();
this->baseMapWidth = baseMapWidth;
this->baseMapHeight = baseMapHeight;
}
void render(qreal opacity = 1) {
QPixmap newPixmap = basePixmap.copy(0, 0, basePixmap.width(), basePixmap.height());
if (opacity < 1) {
QPainter painter(&newPixmap);
int alpha = static_cast<int>(255 * (1 - opacity));
painter.fillRect(0, 0, newPixmap.width(), newPixmap.height(), QColor(0, 0, 0, alpha));
painter.end();
}
this->setPixmap(newPixmap);
}
int getMinOffset();
int getMaxOffset();
QPixmap basePixmap;
Connection* connection;
int initialX;
int initialY;
int initialOffset;
int baseMapWidth;
int baseMapHeight;
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
signals:
void connectionItemSelected(ConnectionPixmapItem* connectionItem);
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
void connectionMoved(Connection*);
};
class MetatilesPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
MetatilesPixmapItem(Map *map_) {
map = map_;
setAcceptHoverEvents(true);
connect(map, SIGNAL(paintTileChanged()), this, SLOT(paintTileChanged()));
}
Map* map = nullptr;
virtual void draw();
private:
void updateSelection(QPointF pos);
protected:
virtual void updateCurHoveredMetatile(QPointF pos);
private slots:
void paintTileChanged();
protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
};
class BorderMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
BorderMetatilesPixmapItem(Map *map_) {
map = map_;
setAcceptHoverEvents(true);
}
Map* map = nullptr;
virtual void draw();
signals:
void borderMetatilesChanged();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
};
class CurrentSelectedMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
CurrentSelectedMetatilesPixmapItem(Map *map_) {
map = map_;
}
Map* map = nullptr;
virtual void draw();
};
class MovementPermissionsPixmapItem : public MetatilesPixmapItem {
Q_OBJECT
public:
MovementPermissionsPixmapItem(Map *map_): MetatilesPixmapItem(map_) {
connect(map, SIGNAL(paintCollisionChanged(Map*)), this, SLOT(paintCollisionChanged(Map *)));
}
virtual void pick(uint16_t collision, uint16_t elevation) {
map->paint_collision = collision;
map->paint_elevation = elevation;
draw();
}
virtual void draw() {
setPixmap(map->renderCollisionMetatiles());
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
virtual void updateCurHoveredMetatile(QPointF pos);
private slots:
void paintCollisionChanged(Map *) {
draw();
}
};
#endif // EDITOR_H

View file

@ -1,286 +1,286 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ObjectPropertiesFrame</class>
<widget class="QFrame" name="ObjectPropertiesFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>284</width>
<height>146</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>284</width>
<height>90</height>
</size>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_spritePixmap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="indent">
<number>-1</number>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_name">
<property name="text">
<string>Object 1</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="x">
<item>
<widget class="QLabel" name="label_x">
<property name="text">
<string>X</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_x">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The X coordinate of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-32768</number>
</property>
<property name="maximum">
<number>32767</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="y">
<item>
<widget class="QLabel" name="label_y">
<property name="text">
<string>Y</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_y">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The Y coordinate of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-32768</number>
</property>
<property name="maximum">
<number>32767</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="z">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Z</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_z">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The elevation of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>15</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="sprite" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout_sprite">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_sprite">
<property name="text">
<string>Sprite</string>
</property>
<property name="buddy">
<cstring>comboBox_sprite</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="NoScrollComboBox" name="comboBox_sprite">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The sprite graphics to use for this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/>
</property>
<property name="maxVisibleItems">
<number>25</number>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NoScrollComboBox</class>
<extends>QComboBox</extends>
<header>noscrollcombobox.h</header>
</customwidget>
<customwidget>
<class>NoScrollSpinBox</class>
<extends>QSpinBox</extends>
<header>noscrollspinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>spinBox_x</tabstop>
<tabstop>spinBox_y</tabstop>
<tabstop>spinBox_z</tabstop>
<tabstop>comboBox_sprite</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EventPropertiesFrame</class>
<widget class="QFrame" name="EventPropertiesFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>284</width>
<height>146</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>284</width>
<height>90</height>
</size>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_spritePixmap">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="indent">
<number>-1</number>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_name">
<property name="text">
<string>Object 1</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="x">
<item>
<widget class="QLabel" name="label_x">
<property name="text">
<string>X</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_x">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The X coordinate of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-32768</number>
</property>
<property name="maximum">
<number>32767</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="y">
<item>
<widget class="QLabel" name="label_y">
<property name="text">
<string>Y</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_y">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The Y coordinate of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-32768</number>
</property>
<property name="maximum">
<number>32767</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="z">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Z</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="NoScrollSpinBox" name="spinBox_z">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The elevation of this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>15</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="sprite" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout_sprite">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_sprite">
<property name="text">
<string>Sprite</string>
</property>
<property name="buddy">
<cstring>comboBox_sprite</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="NoScrollComboBox" name="comboBox_sprite">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The sprite graphics to use for this object.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/>
</property>
<property name="maxVisibleItems">
<number>25</number>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NoScrollComboBox</class>
<extends>QComboBox</extends>
<header>noscrollcombobox.h</header>
</customwidget>
<customwidget>
<class>NoScrollSpinBox</class>
<extends>QSpinBox</extends>
<header>noscrollspinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>spinBox_x</tabstop>
<tabstop>spinBox_y</tabstop>
<tabstop>spinBox_z</tabstop>
<tabstop>comboBox_sprite</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

4595
mainwindow.ui → forms/mainwindow.ui Executable file → Normal file

File diff suppressed because it is too large Load diff

1536
forms/paletteeditor.ui Normal file

File diff suppressed because it is too large Load diff

445
forms/tileseteditor.ui Normal file
View file

@ -0,0 +1,445 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TilesetEditor</class>
<widget class="QMainWindow" name="TilesetEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QScrollArea" name="scrollArea_Metatiles">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>386</width>
<height>539</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Metatiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignTop">
<widget class="QFrame" name="frame_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Tile Properties</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Palette</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox_paletteSelector"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>X Flip</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Y Flip</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Selection</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_xFlip">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBox_yFlip">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QGraphicsView" name="graphicsView_selectedTile">
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Metatile Properties</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Bottom/Top</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGraphicsView" name="graphicsView_metatileLayers">
<property name="minimumSize">
<size>
<width>64</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>32</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Metatile Behavior</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QComboBox" name="comboBox_metatileBehaviors"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Layer Type</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QComboBox" name="comboBox_layerType"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_Tiles">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>386</width>
<height>359</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Tiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionSave_Tileset"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionImport_Primary_Tiles"/>
<addaction name="actionImport_Secondary_Tiles"/>
<addaction name="actionChange_Metatiles_Count"/>
<addaction name="actionChange_Palettes"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuTools"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionSave_Tileset">
<property name="text">
<string>Save Tileset</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionImport_Primary_Tiles">
<property name="text">
<string>Import Primary Tiles</string>
</property>
</action>
<action name="actionImport_Secondary_Tiles">
<property name="text">
<string>Import Secondary Tiles</string>
</property>
</action>
<action name="actionChange_Metatiles_Count">
<property name="text">
<string>Change Number of Metatiles</string>
</property>
</action>
<action name="actionChange_Palettes">
<property name="text">
<string>Change Palettes</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

40
block.h → include/core/block.h Executable file → Normal file
View file

@ -1,20 +1,20 @@
#ifndef BLOCK_H
#define BLOCK_H
#include <QObject>
class Block
{
public:
Block();
Block(uint16_t);
Block(const Block&);
bool operator ==(Block);
bool operator !=(Block);
uint16_t tile:10;
uint16_t collision:2;
uint16_t elevation:4;
uint16_t rawValue();
};
#endif // BLOCK_H
#ifndef BLOCK_H
#define BLOCK_H
#include <QObject>
class Block
{
public:
Block();
Block(uint16_t);
Block(const Block&);
bool operator ==(Block);
bool operator !=(Block);
uint16_t tile:10;
uint16_t collision:2;
uint16_t elevation:4;
uint16_t rawValue();
};
#endif // BLOCK_H

64
blockdata.h → include/core/blockdata.h Executable file → Normal file
View file

@ -1,32 +1,32 @@
#ifndef BLOCKDATA_H
#define BLOCKDATA_H
#include "block.h"
#include <QObject>
#include <QByteArray>
class Blockdata : public QObject
{
Q_OBJECT
public:
explicit Blockdata(QObject *parent = nullptr);
~Blockdata() {
if (blocks) delete blocks;
}
public:
QList<Block> *blocks = nullptr;
void addBlock(uint16_t);
void addBlock(Block);
QByteArray serialize();
void copyFrom(Blockdata*);
Blockdata* copy();
bool equals(Blockdata *);
signals:
public slots:
};
#endif // BLOCKDATA_H
#ifndef BLOCKDATA_H
#define BLOCKDATA_H
#include "block.h"
#include <QObject>
#include <QByteArray>
class Blockdata : public QObject
{
Q_OBJECT
public:
explicit Blockdata(QObject *parent = nullptr);
~Blockdata() {
if (blocks) delete blocks;
}
public:
QList<Block> *blocks = nullptr;
void addBlock(uint16_t);
void addBlock(Block);
QByteArray serialize();
void copyFrom(Blockdata*);
Blockdata* copy();
bool equals(Blockdata *);
signals:
public slots:
};
#endif // BLOCKDATA_H

172
event.h → include/core/event.h Executable file → Normal file
View file

@ -1,87 +1,85 @@
#ifndef EVENT_H
#define EVENT_H
#include "heallocation.h"
#include <QString>
#include <QPixmap>
#include <QMap>
#include <QDebug>
class EventType
{
public:
static QString Object;
static QString Warp;
static QString CoordScript;
static QString CoordWeather;
static QString Sign;
static QString HiddenItem;
static QString SecretBase;
static QString HealLocation;
};
class Event
{
public:
Event();
public:
int x() {
return getInt("x");
}
int y() {
return getInt("y");
}
int elevation() {
return getInt("elevation");
}
void setX(int x) {
put("x", x);
}
void setY(int y) {
put("y", y);
}
QString get(QString key) {
return values.value(key);
}
int getInt(QString key) {
return values.value(key).toInt(nullptr, 0);
}
uint16_t getU16(QString key) {
return values.value(key).toUShort(nullptr, 0);
}
void put(QString key, int value) {
put(key, QString("%1").arg(value));
}
void put(QString key, QString value) {
values.insert(key, value);
}
static Event* createNewEvent(QString, QString);
static Event* createNewObjectEvent();
static Event* createNewWarpEvent(QString);
static Event* createNewHealLocationEvent(QString);
static Event* createNewCoordScriptEvent();
static Event* createNewCoordWeatherEvent();
static Event* createNewSignEvent();
static Event* createNewHiddenItemEvent();
static Event* createNewSecretBaseEvent();
QString buildObjectEventMacro(int);
QString buildWarpEventMacro(QMap<QString, QString>*);
HealLocation buildHealLocation();
QString buildCoordScriptEventMacro();
QString buildCoordWeatherEventMacro();
QString buildSignEventMacro();
QString buildHiddenItemEventMacro();
QString buildSecretBaseEventMacro();
void setPixmapFromSpritesheet(QImage, int, int);
int getPixelX();
int getPixelY();
QMap<QString, QString> values;
QPixmap pixmap;
int spriteWidth;
int spriteHeight;
};
#endif // EVENT_H
#ifndef EVENT_H
#define EVENT_H
#include <QString>
#include <QPixmap>
#include <QMap>
#include <QDebug>
class EventType
{
public:
static QString Object;
static QString Warp;
static QString CoordScript;
static QString CoordWeather;
static QString Sign;
static QString HiddenItem;
static QString SecretBase;
static QString HealLocation;
};
class Event
{
public:
Event();
public:
int x() {
return getInt("x");
}
int y() {
return getInt("y");
}
int elevation() {
return getInt("elevation");
}
void setX(int x) {
put("x", x);
}
void setY(int y) {
put("y", y);
}
QString get(QString key) {
return values.value(key);
}
int getInt(QString key) {
return values.value(key).toInt(nullptr, 0);
}
uint16_t getU16(QString key) {
return values.value(key).toUShort(nullptr, 0);
}
void put(QString key, int value) {
put(key, QString("%1").arg(value));
}
void put(QString key, QString value) {
values.insert(key, value);
}
static Event* createNewEvent(QString, QString);
static Event* createNewObjectEvent();
static Event* createNewWarpEvent(QString);
static Event* createNewHealLocationEvent(QString);
static Event* createNewCoordScriptEvent();
static Event* createNewCoordWeatherEvent();
static Event* createNewSignEvent();
static Event* createNewHiddenItemEvent();
static Event* createNewSecretBaseEvent();
QString buildObjectEventMacro(int);
QString buildWarpEventMacro(QMap<QString, QString>*);
QString buildCoordScriptEventMacro();
QString buildCoordWeatherEventMacro();
QString buildSignEventMacro();
QString buildHiddenItemEventMacro();
QString buildSecretBaseEventMacro();
void setPixmapFromSpritesheet(QImage, int, int);
int getPixelX();
int getPixelY();
QMap<QString, QString> values;
QPixmap pixmap;
int spriteWidth;
int spriteHeight;
};
#endif // EVENT_H

View file

@ -1,6 +1,7 @@
#ifndef HEALLOCATION_H
#define HEALLOCATION_H
#include "event.h"
#include <QString>
#include <QDebug>
@ -17,7 +18,7 @@ public:
int index;
uint16_t x;
uint16_t y;
static HealLocation fromEvent(Event*);
};
#endif // HEALLOCATION_H

58
include/core/history.h Normal file
View file

@ -0,0 +1,58 @@
#ifndef HISTORY_H
#define HISTORY_H
#include <QList>
template <typename T>
class History {
public:
History() { }
T back() {
if (head > 0) {
return history.at(--head);
}
return NULL;
}
T next() {
if (head + 1 < history.length()) {
return history.at(++head);
}
return NULL;
}
void push(T commit) {
while (head + 1 < history.length()) {
T item = history.last();
history.removeLast();
delete item;
}
if (saved > head) {
saved = -1;
}
history.append(commit);
head++;
}
T current() {
if (head < 0 || history.length() == 0) {
return NULL;
}
return history.at(head);
}
void save() {
saved = head;
}
bool isSaved() {
return saved == head;
}
private:
QList<T> history;
int head = -1;
int saved = -1;
};
#endif // HISTORY_H

View file

@ -0,0 +1,15 @@
#ifndef HISTORYITEM_H
#define HISTORYITEM_H
#include "blockdata.h"
class HistoryItem {
public:
Blockdata *metatiles;
int layoutWidth;
int layoutHeight;
HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight);
~HistoryItem();
};
#endif // HISTORYITEM_H

89
include/core/map.h Normal file
View file

@ -0,0 +1,89 @@
#ifndef MAP_H
#define MAP_H
#include "blockdata.h"
#include "history.h"
#include "historyitem.h"
#include "mapconnection.h"
#include "maplayout.h"
#include "tileset.h"
#include "event.h"
#include <QPixmap>
#include <QObject>
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <math.h>
class Map : public QObject
{
Q_OBJECT
public:
explicit Map(QObject *parent = nullptr);
public:
QString name;
QString constantName;
QString group_num;
QString layout_label;
QString events_label;
QString scripts_label;
QString connections_label;
QString song;
QString layout_id;
QString location;
QString requiresFlash;
QString isFlyable; // TODO: implement this
QString weather;
QString type;
QString unknown;
QString show_location;
QString battle_scene;
MapLayout *layout;
bool isPersistedToFile = true;
QImage collision_image;
QPixmap collision_pixmap;
QImage image;
QPixmap pixmap;
History<HistoryItem*> metatileHistory;
QMap<QString, QList<Event*>> events;
QList<MapConnection*> connections;
void setName(QString mapName);
static QString mapConstantFromName(QString mapName);
static QString objectEventsLabelFromName(QString mapName);
static QString warpEventsLabelFromName(QString mapName);
static QString coordEventsLabelFromName(QString mapName);
static QString bgEventsLabelFromName(QString mapName);
int getWidth();
int getHeight();
QPixmap render(bool ignoreCache);
QPixmap renderCollision(bool ignoreCache);
bool blockChanged(int, Blockdata*);
void cacheBlockdata();
void cacheCollision();
Block *getBlock(int x, int y);
void setBlock(int x, int y, Block block);
void _setBlock(int x, int y, Block block);
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void undo();
void redo();
void commit();
QList<Event*> getAllEvents();
void removeEvent(Event*);
void addEvent(Event*);
QPixmap renderConnection(MapConnection);
QPixmap renderBorder();
void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true);
void cacheBorder();
bool hasUnsavedChanges();
private:
void setNewDimensionsBlockdata(int newWidth, int newHeight);
signals:
void mapChanged(Map *map);
void mapNeedsRedrawing();
};
#endif // MAP_H

View file

@ -0,0 +1,14 @@
#ifndef MAPCONNECTION_H
#define MAPCONNECTION_H
#include <QString>
#include <QDebug>
class MapConnection {
public:
QString direction;
QString offset;
QString map_name;
};
#endif // MAPCONNECTION_H

41
include/core/maplayout.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef MAPLAYOUT_H
#define MAPLAYOUT_H
#include "blockdata.h"
#include "tileset.h"
#include <QImage>
#include <QPixmap>
#include <QString>
class MapLayout {
public:
MapLayout() {}
int index;
QString name;
QString label;
QString width;
QString height;
QString border_label;
QString border_path;
QString blockdata_label;
QString blockdata_path;
QString tileset_primary_label;
QString tileset_secondary_label;
Tileset *tileset_primary = nullptr;
Tileset *tileset_secondary = nullptr;
Blockdata* blockdata = nullptr;
QImage border_image;
QPixmap border_pixmap;
Blockdata *border = nullptr;
Blockdata *cached_blockdata = nullptr;
Blockdata *cached_collision = nullptr;
Blockdata *cached_border = nullptr;
bool has_unsaved_changes = false;
public:
static QString getNameFromLabel(QString label) {
// ASSUMPTION: strip off "_Layout" from layout label. Directories in 'data/layouts/' must be well-formed.
return label.replace(label.lastIndexOf("_Layout"), label.length(), "");
}
};
#endif // MAPLAYOUT_H

20
include/core/metatile.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef METATILE_H
#define METATILE_H
#include "tile.h"
#include <QImage>
class Metatile
{
public:
Metatile();
public:
QList<Tile> *tiles = nullptr;
uint8_t behavior;
uint8_t layerType;
Metatile *copy();
static int getBlockIndex(int);
};
#endif // METATILE_H

94
parseutil.h → include/core/parseutil.h Executable file → Normal file
View file

@ -1,47 +1,47 @@
#ifndef PARSEUTIL_H
#define PARSEUTIL_H
#include "heallocation.h"
#include <QString>
#include <QList>
#include <QMap>
enum TokenType {
Number,
Operator,
};
class Token {
public:
Token(QString value = "", QString type = "") {
this->value = value;
this->type = TokenType::Operator;
if (type == "decimal" || type == "hex") {
this->type = TokenType::Number;
this->operatorPrecedence = -1;
} else if (type == "operator") {
this->operatorPrecedence = precedenceMap[value];
}
}
static QMap<QString, int> precedenceMap;
QString value;
TokenType type;
int operatorPrecedence; // only relevant for operator tokens
};
class ParseUtil
{
public:
ParseUtil();
void strip_comment(QString*);
QList<QStringList>* parseAsm(QString);
int evaluateDefine(QString, QMap<QString, int>*);
QList<HealLocation>* parseHealLocs(QString);
private:
QList<Token> tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers);
QList<Token> generatePostfix(QList<Token> tokens);
int evaluatePostfix(QList<Token> postfix);
};
#endif // PARSEUTIL_H
#ifndef PARSEUTIL_H
#define PARSEUTIL_H
#include "heallocation.h"
#include <QString>
#include <QList>
#include <QMap>
enum TokenType {
Number,
Operator,
};
class Token {
public:
Token(QString value = "", QString type = "") {
this->value = value;
this->type = TokenType::Operator;
if (type == "decimal" || type == "hex") {
this->type = TokenType::Number;
this->operatorPrecedence = -1;
} else if (type == "operator") {
this->operatorPrecedence = precedenceMap[value];
}
}
static QMap<QString, int> precedenceMap;
QString value;
TokenType type;
int operatorPrecedence; // only relevant for operator tokens
};
class ParseUtil
{
public:
ParseUtil();
void strip_comment(QString*);
QList<QStringList>* parseAsm(QString);
int evaluateDefine(QString, QMap<QString, int>*);
QList<HealLocation>* parseHealLocs(QString);
private:
QList<Token> tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers);
QList<Token> generatePostfix(QList<Token> tokens);
int evaluatePostfix(QList<Token> postfix);
};
#endif // PARSEUTIL_H

32
tile.h → include/core/tile.h Executable file → Normal file
View file

@ -1,16 +1,16 @@
#ifndef TILE_H
#define TILE_H
class Tile
{
public:
Tile();
public:
int tile;
int xflip;
int yflip;
int palette;
};
#endif // TILE_H
#ifndef TILE_H
#define TILE_H
class Tile
{
public:
Tile();
public:
int tile;
int xflip;
int yflip;
int palette;
};
#endif // TILE_H

85
tileset.h → include/core/tileset.h Executable file → Normal file
View file

@ -1,45 +1,40 @@
#ifndef TILESET_H
#define TILESET_H
#include "tile.h"
#include <QImage>
class Metatile;
class Tileset
{
public:
Tileset();
public:
QString name;
QString is_compressed;
QString is_secondary;
QString padding;
QString tiles_label;
QString palettes_label;
QString metatiles_label;
QString callback_label;
QString metatile_attrs_label;
QList<QImage> *tiles = nullptr;
QList<Metatile*> *metatiles = nullptr;
QList<QList<QRgb>> *palettes = nullptr;
};
class Metatile
{
public:
Metatile();
public:
QList<Tile> *tiles = nullptr;
int attr;
static QImage getMetatileImage(int, Tileset*, Tileset*);
static Metatile* getMetatile(int, Tileset*, Tileset*);
static QImage getMetatileTile(int, Tileset*, Tileset*);
static Tileset* getBlockTileset(int, Tileset*, Tileset*);
static int getBlockIndex(int);
static QList<QList<QRgb>> getBlockPalettes(Tileset*, Tileset*);
};
#endif // TILESET_H
#ifndef TILESET_H
#define TILESET_H
#include "metatile.h"
#include "tile.h"
#include <QImage>
class Tileset
{
public:
Tileset();
public:
QString name;
QString is_compressed;
QString is_secondary;
QString padding;
QString tiles_label;
QString palettes_label;
QString metatiles_label;
QString metatiles_path;
QString callback_label;
QString metatile_attrs_label;
QString metatile_attrs_path;
QString tilesImagePath;
QImage tilesImage;
QList<QString> palettePaths;
QList<QImage> *tiles = nullptr;
QList<Metatile*> *metatiles = nullptr;
QList<QList<QRgb>> *palettes = nullptr;
Tileset* copy();
static Tileset* getBlockTileset(int, Tileset*, Tileset*);
static Metatile* getMetatile(int, Tileset*, Tileset*);
static QList<QList<QRgb>> getBlockPalettes(Tileset*, Tileset*);
static QList<QRgb> getPalette(int, Tileset*, Tileset*);
};
#endif // TILESET_H

264
include/editor.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef EDITOR_H
#define EDITOR_H
#include <QGraphicsScene>
#include <QGraphicsItemGroup>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsItemAnimation>
#include <QComboBox>
#include <QCheckBox>
#include <QCursor>
#include "mapconnection.h"
#include "metatileselector.h"
#include "movementpermissionsselector.h"
#include "project.h"
#include "ui_mainwindow.h"
#include "bordermetatilespixmapitem.h"
#include "connectionpixmapitem.h"
#include "currentselectedmetatilespixmapitem.h"
#include "collisionpixmapitem.h"
#include "mappixmapitem.h"
#include "settings.h"
class DraggablePixmapItem;
class MetatilesPixmapItem;
class Editor : public QObject
{
Q_OBJECT
public:
Editor(Ui::MainWindow* ui);
public:
Ui::MainWindow* ui;
QObject *parent = nullptr;
Project *project = nullptr;
Map *map = nullptr;
Settings *settings;
void saveProject();
void save();
void undo();
void redo();
void setMap(QString map_name);
void displayMap();
void displayMetatileSelector();
void displayMapMetatiles();
void displayMapMovementPermissions();
void displayBorderMetatiles();
void displayCurrentMetatilesSelection();
void redrawCurrentMetatilesSelection();
void displayMovementPermissionSelector();
void displayElevationMetatiles();
void displayMapEvents();
void displayMapConnections();
void displayMapBorder();
void displayMapGrid();
void setEditingMap();
void setEditingCollision();
void setEditingObjects();
void setEditingConnections();
void setCurrentConnectionDirection(QString curDirection);
void updateCurrentConnectionDirection(QString curDirection);
void setConnectionsVisibility(bool visible);
void updateConnectionOffset(int offset);
void setConnectionMap(QString mapName);
void addNewConnection();
void removeCurrentConnection();
void updateDiveMap(QString mapName);
void updateEmergeMap(QString mapName);
void setSelectedConnectionFromMap(QString mapName);
void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false);
void updateSecondaryTileset(QString tilesetLabel, bool forceLoad = false);
void toggleBorderVisibility(bool visible);
Tileset *getCurrentMapPrimaryTileset();
DraggablePixmapItem *addMapEvent(Event *event);
void selectMapEvent(DraggablePixmapItem *object);
void selectMapEvent(DraggablePixmapItem *object, bool toggle);
DraggablePixmapItem *addNewEvent(QString event_type);
Event* createNewEvent(QString event_type);
void deleteEvent(Event *);
void updateSelectedEvents();
void redrawObject(DraggablePixmapItem *item);
QList<DraggablePixmapItem *> *getObjects();
QGraphicsScene *scene = nullptr;
QGraphicsPixmapItem *current_view = nullptr;
MapPixmapItem *map_item = nullptr;
ConnectionPixmapItem* selected_connection_item = nullptr;
QList<QGraphicsPixmapItem*> connection_items;
QList<ConnectionPixmapItem*> connection_edit_items;
CollisionPixmapItem *collision_item = nullptr;
QGraphicsItemGroup *events_group = nullptr;
QList<QGraphicsPixmapItem*> borderItems;
QList<QGraphicsLineItem*> gridLines;
QGraphicsScene *scene_metatiles = nullptr;
QGraphicsScene *scene_current_metatile_selection = nullptr;
QGraphicsScene *scene_selected_border_metatiles = nullptr;
QGraphicsScene *scene_collision_metatiles = nullptr;
QGraphicsScene *scene_elevation_metatiles = nullptr;
MetatileSelector *metatile_selector_item = nullptr;
BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr;
CurrentSelectedMetatilesPixmapItem *scene_current_metatile_selection_item = nullptr;
MovementPermissionsSelector *movement_permissions_selector_item = nullptr;
QList<DraggablePixmapItem*> *events = nullptr;
QList<DraggablePixmapItem*> *selected_events = nullptr;
QString map_edit_mode;
QString prev_edit_mode;
int scale_exp = 0;
double scale_base = sqrt(2); // adjust scale factor with this
void objectsView_onMousePress(QMouseEvent *event);
void objectsView_onMouseMove(QMouseEvent *event);
void objectsView_onMouseRelease(QMouseEvent *event);
private:
void setConnectionItemsVisible(bool);
void setBorderItemsVisible(bool, qreal = 1);
void setConnectionEditControlValues(MapConnection*);
void setConnectionEditControlsEnabled(bool);
void createConnectionItem(MapConnection* connection, bool hide);
void populateConnectionMapPickers();
void setDiveEmergeControls();
void updateDiveEmergeMap(QString mapName, QString direction);
void onConnectionOffsetChanged(int newOffset);
void removeMirroredConnection(MapConnection*);
void updateMirroredConnectionOffset(MapConnection*);
void updateMirroredConnectionDirection(MapConnection*, QString);
void updateMirroredConnectionMap(MapConnection*, QString);
void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false);
Event* createNewObjectEvent();
Event* createNewWarpEvent();
Event* createNewHealLocationEvent();
Event* createNewCoordScriptEvent();
Event* createNewCoordWeatherEvent();
Event* createNewSignEvent();
Event* createNewHiddenItemEvent();
Event* createNewSecretBaseEvent();
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
private slots:
void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item);
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
void onConnectionMoved(MapConnection*);
void onConnectionItemSelected(ConnectionPixmapItem* connectionItem);
void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
void onConnectionDirectionChanged(QString newDirection);
void onBorderMetatilesChanged();
void onHoveredMovementPermissionChanged(uint16_t, uint16_t);
void onHoveredMovementPermissionCleared();
void onHoveredMetatileSelectionChanged(uint16_t);
void onHoveredMetatileSelectionCleared();
void onHoveredMapMetatileChanged(int, int);
void onHoveredMapMetatileCleared();
void onHoveredMapMovementPermissionChanged(int, int);
void onHoveredMapMovementPermissionCleared();
void onSelectedMetatilesChanged();
signals:
void objectsChanged();
void selectedObjectsChanged();
void loadMapRequested(QString, QString);
void tilesetChanged(QString);
void warpEventDoubleClicked(QString mapName, QString warpNum);
void currentMetatilesSelectionChanged();
void wheelZoom(int delta);
};
class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
}
Editor *editor = nullptr;
Event *event = nullptr;
QGraphicsItemAnimation *pos_anim = nullptr;
DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) {
event = event_;
editor = editor_;
updatePosition();
}
bool active;
int last_x;
int last_y;
void updatePosition() {
int x = event->getPixelX();
int y = event->getPixelY();
setX(x);
setY(y);
setZValue(event->y());
}
void move(int x, int y);
void emitPositionChanged() {
emit xChanged(event->x());
emit yChanged(event->y());
emit elevationChanged(event->elevation());
}
void updatePixmap() {
QList<Event*> objects;
objects.append(event);
event->pixmap = QPixmap();
editor->project->loadEventPixmaps(objects);
this->updatePosition();
editor->redrawObject(this);
emit spriteChanged(event->pixmap);
}
void bind(QComboBox *combo, QString key) {
connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
this, [this, key](QString value){
this->event->put(key, value);
});
connect(this, &DraggablePixmapItem::onPropertyChanged,
this, [combo, key](QString key2, QString value){
if (key2 == key) {
combo->addItem(value);
combo->setCurrentText(value);
}
});
}
signals:
void positionChanged(Event *event);
void xChanged(int);
void yChanged(int);
void elevationChanged(int);
void spriteChanged(QPixmap pixmap);
void onPropertyChanged(QString key, QString value);
public slots:
void set_x(const QString &text) {
event->put("x", text);
updatePosition();
}
void set_y(const QString &text) {
event->put("y", text);
updatePosition();
}
void set_elevation(const QString &text) {
event->put("elevation", text);
updatePosition();
}
void set_sprite(const QString &text) {
event->put("sprite", text);
updatePixmap();
}
void set_script(const QString &text) {
event->put("script_label", text);
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
};
#endif // EDITOR_H

324
mainwindow.h → include/mainwindow.h Executable file → Normal file
View file

@ -1,155 +1,169 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QString>
#include <QModelIndex>
#include <QMainWindow>
#include <QStandardItemModel>
#include <QGraphicsPixmapItem>
#include <QGraphicsItemGroup>
#include <QGraphicsSceneMouseEvent>
#include <QAbstractItemModel>
#include "project.h"
#include "map.h"
#include "editor.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void setStatusBarMessage(QString message, int timeout = 0);
private slots:
void on_action_Open_Project_triggered();
void on_mapList_activated(const QModelIndex &index);
void on_action_Save_Project_triggered();
void openWarpMap(QString map_name, QString warp_num);
void undo();
void redo();
void openInTextEditor();
void onLoadMapRequested(QString, QString);
void onMapChanged(Map *map);
void onMapNeedsRedrawing();
void on_action_Save_triggered();
void on_tabWidget_2_currentChanged(int index);
void on_action_Exit_triggered();
void on_comboBox_Song_activated(const QString &arg1);
void on_comboBox_Location_activated(const QString &arg1);
void on_comboBox_Visibility_activated(const QString &arg1);
void on_comboBox_Weather_activated(const QString &arg1);
void on_comboBox_Type_activated(const QString &arg1);
void on_comboBox_BattleScene_activated(const QString &arg1);
void on_checkBox_ShowLocation_clicked(bool checked);
void on_tabWidget_currentChanged(int index);
void on_actionUndo_triggered();
void on_actionRedo_triggered();
void on_actionZoom_In_triggered();
void on_actionZoom_Out_triggered();
void on_actionBetter_Cursors_triggered();
void on_actionPencil_triggered();
void on_actionPointer_triggered();
void on_actionFlood_Fill_triggered();
void on_actionEyedropper_triggered();
void on_actionMove_triggered();
void on_actionMap_Shift_triggered();
void on_toolButton_deleteObject_clicked();
void on_toolButton_Open_Scripts_clicked();
void addNewEvent(QString);
void updateSelectedObjects();
void on_toolButton_Paint_clicked();
void on_toolButton_Select_clicked();
void on_toolButton_Fill_clicked();
void on_toolButton_Dropper_clicked();
void on_toolButton_Move_clicked();
void on_toolButton_Shift_clicked();
void onOpenMapListContextMenu(const QPoint &point);
void onAddNewMapToGroupClick(QAction* triggeredAction);
void onTilesetChanged(QString);
void currentMetatilesSelectionChanged();
void on_action_Export_Map_Image_triggered();
void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1);
void on_spinBox_ConnectionOffset_valueChanged(int offset);
void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName);
void on_pushButton_AddConnection_clicked();
void on_pushButton_RemoveConnection_clicked();
void on_comboBox_DiveMap_currentTextChanged(const QString &mapName);
void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName);
void on_comboBox_PrimaryTileset_activated(const QString &arg1);
void on_comboBox_SecondaryTileset_activated(const QString &arg1);
void on_pushButton_clicked();
void on_checkBox_smartPaths_stateChanged(int selected);
void on_checkBox_Visibility_clicked(bool checked);
void on_checkBox_ToggleBorder_stateChanged(int arg1);
private:
Ui::MainWindow *ui;
QStandardItemModel *mapListModel;
QList<QStandardItem*> *mapGroupsModel;
Editor *editor = nullptr;
QIcon* mapIcon;
void setMap(QString);
void redrawMapScene();
void loadDataStructures();
void populateMapList();
QString getExistingDirectory(QString);
void openProject(QString dir);
QString getDefaultMap();
void setRecentMap(QString map_name);
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
void markAllEdited(QAbstractItemModel *model);
void markEdited(QModelIndex index);
void updateMapList();
void displayMapProperties();
void checkToolButtons();
void scaleMapView(int);
};
enum MapListUserRoles {
GroupRole = Qt::UserRole + 1, // Used to hold the map group number.
TypeRole = Qt::UserRole + 2, // Used to differentiate between the different layers of the map list tree view.
};
#endif // MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QString>
#include <QModelIndex>
#include <QMainWindow>
#include <QStandardItemModel>
#include <QGraphicsPixmapItem>
#include <QGraphicsItemGroup>
#include <QGraphicsSceneMouseEvent>
#include <QAbstractItemModel>
#include "project.h"
#include "map.h"
#include "editor.h"
#include "tileseteditor.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void scaleMapView(int);
private slots:
void on_action_Open_Project_triggered();
void on_mapList_activated(const QModelIndex &index);
void on_action_Save_Project_triggered();
void openWarpMap(QString map_name, QString warp_num);
void undo();
void redo();
void openInTextEditor();
void onLoadMapRequested(QString, QString);
void onMapChanged(Map *map);
void onMapNeedsRedrawing();
void onTilesetsSaved(QString, QString);
void on_action_Save_triggered();
void on_tabWidget_2_currentChanged(int index);
void on_action_Exit_triggered();
void on_comboBox_Song_activated(const QString &arg1);
void on_comboBox_Location_activated(const QString &arg1);
void on_comboBox_Visibility_activated(const QString &arg1);
void on_comboBox_Weather_activated(const QString &arg1);
void on_comboBox_Type_activated(const QString &arg1);
void on_comboBox_BattleScene_activated(const QString &arg1);
void on_checkBox_ShowLocation_clicked(bool checked);
void on_tabWidget_currentChanged(int index);
void on_actionUndo_triggered();
void on_actionRedo_triggered();
void on_actionZoom_In_triggered();
void on_actionZoom_Out_triggered();
void on_actionBetter_Cursors_triggered();
void on_actionPencil_triggered();
void on_actionPointer_triggered();
void on_actionFlood_Fill_triggered();
void on_actionEyedropper_triggered();
void on_actionMove_triggered();
void on_actionMap_Shift_triggered();
void on_toolButton_deleteObject_clicked();
void on_toolButton_Open_Scripts_clicked();
void addNewEvent(QString);
void updateSelectedObjects();
void on_toolButton_Paint_clicked();
void on_toolButton_Select_clicked();
void on_toolButton_Fill_clicked();
void on_toolButton_Dropper_clicked();
void on_toolButton_Move_clicked();
void on_toolButton_Shift_clicked();
void onOpenMapListContextMenu(const QPoint &point);
void onAddNewMapToGroupClick(QAction* triggeredAction);
void onTilesetChanged(QString);
void currentMetatilesSelectionChanged();
void onTilesetEditorClosed();
void on_action_Export_Map_Image_triggered();
void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1);
void on_spinBox_ConnectionOffset_valueChanged(int offset);
void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName);
void on_pushButton_AddConnection_clicked();
void on_pushButton_RemoveConnection_clicked();
void on_comboBox_DiveMap_currentTextChanged(const QString &mapName);
void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName);
void on_comboBox_PrimaryTileset_activated(const QString &arg1);
void on_comboBox_SecondaryTileset_activated(const QString &arg1);
void on_pushButton_clicked();
void on_checkBox_smartPaths_stateChanged(int selected);
void on_checkBox_Visibility_clicked(bool checked);
void on_checkBox_ToggleBorder_stateChanged(int arg1);
void resetMapViewScale();
void on_actionTileset_Editor_triggered();
private:
Ui::MainWindow *ui;
TilesetEditor *tilesetEditor = nullptr;
QStandardItemModel *mapListModel;
QList<QStandardItem*> *mapGroupsModel;
QMap<QString, QModelIndex> mapListIndexes;
Editor *editor = nullptr;
QIcon* mapIcon;
void setMap(QString, bool scrollTreeView = false);
void redrawMapScene();
void loadDataStructures();
void populateMapList();
QString getExistingDirectory(QString);
void openProject(QString dir);
QString getDefaultMap();
void setRecentMap(QString map_name);
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
void markAllEdited(QAbstractItemModel *model);
void markEdited(QModelIndex index);
void updateMapList();
void displayMapProperties();
void checkToolButtons();
void initExtraShortcuts();
void initExtraSignals();
void initEditor();
void loadUserSettings();
void openRecentProject();
void updateTilesetEditor();
};
enum MapListUserRoles {
GroupRole = Qt::UserRole + 1, // Used to hold the map group number.
TypeRole = Qt::UserRole + 2, // Used to differentiate between the different layers of the map list tree view.
};
#endif // MAINWINDOW_H

315
project.h → include/project.h Executable file → Normal file
View file

@ -1,152 +1,163 @@
#ifndef PROJECT_H
#define PROJECT_H
#include "map.h"
#include "blockdata.h"
#include "heallocation.h"
#include <QStringList>
#include <QList>
#include <QStandardItem>
static QString NONE_MAP_CONSTANT = "MAP_NONE";
static QString NONE_MAP_NAME = "None";
class Project
{
public:
Project();
QString root;
QStringList *groupNames = nullptr;
QMap<QString, int> *map_groups;
QList<QStringList> groupedMapNames;
QStringList *mapNames = nullptr;
QList<HealLocation> flyableMaps;
QMap<QString, QString>* mapConstantsToMapNames;
QMap<QString, QString>* mapNamesToMapConstants;
QList<QString> mapLayoutsTable;
QList<QString> mapLayoutsTableMaster;
QMap<QString, MapLayout*> mapLayouts;
QMap<QString, MapLayout*> mapLayoutsMaster;
QStringList *regionMapSections = nullptr;
QStringList *itemNames = nullptr;
QStringList *flagNames = nullptr;
QStringList *varNames = nullptr;
QStringList *movementTypes = nullptr;
QStringList *mapTypes = nullptr;
QStringList *mapBattleScenes = nullptr;
QStringList *weatherNames = nullptr;
QStringList *coordEventWeatherNames = nullptr;
QStringList *secretBaseIds = nullptr;
QStringList *bgEventFacingDirections = nullptr;
QStringList mapsWithConnections;
QMap<QString, Map*> *map_cache;
Map* loadMap(QString);
Map* getMap(QString);
QMap<QString, Tileset*> *tileset_cache = nullptr;
Tileset* loadTileset(QString);
Tileset* getTileset(QString);
Blockdata* readBlockdata(QString);
void loadBlockdata(Map*);
QString readTextFile(QString path);
void saveTextFile(QString path, QString text);
void appendTextFile(QString path, QString text);
void deleteFile(QString path);
void readMapGroups();
Map* addNewMapToGroup(QString mapName, int groupNum);
QString getNewMapName();
QString getProjectTitle();
QList<QStringList>* getLabelMacros(QList<QStringList>*, QString);
QStringList* getLabelValues(QList<QStringList>*, QString);
void readMapHeader(Map*);
void readMapLayoutsTable();
void readAllMapLayouts();
QStringList* readLayoutValues(QString layoutName);
void readMapLayout(Map*);
void readMapsWithConnections();
void loadMapTilesets(Map*);
void loadTilesetAssets(Tileset*);
void saveBlockdata(Map*);
void saveMapBorder(Map*);
void writeBlockdata(QString, Blockdata*);
void saveAllMaps();
void saveMap(Map*);
void saveAllDataStructures();
void saveAllMapLayouts();
void saveMapGroupsTable();
void saveMapConstantsHeader();
void saveHealLocationStruct(Map*);
QList<QStringList>* parseAsm(QString text);
QStringList getSongNames();
QStringList getVisibilities();
QMap<QString, QStringList> getTilesets();
void readTilesetProperties();
void readRegionMapSections();
void readItemNames();
void readFlagNames();
void readVarNames();
void readMovementTypes();
void readMapTypes();
void readMapBattleScenes();
void readWeatherNames();
void readCoordEventWeatherNames();
void readSecretBaseIds();
void readBgEventFacingDirections();
void loadEventPixmaps(QList<Event*> objects);
QMap<QString, int> getEventObjGfxConstants();
QString fixGraphicPath(QString path);
void readMapEvents(Map *map);
void loadMapConnections(Map *map);
void loadMapBorder(Map *map);
void saveMapEvents(Map *map);
QStringList readCArray(QString text, QString label);
QString readCIncbin(QString text, QString label);
QMap<QString, int> readCDefines(QString text, QStringList prefixes);
static int getNumTilesPrimary();
static int getNumTilesTotal();
static int getNumMetatilesPrimary();
static int getNumMetatilesTotal();
static int getNumPalettesPrimary();
static int getNumPalettesTotal();
private:
QString getMapLayoutsTableFilepath();
QString getMapLayoutFilepath(QString);
void saveMapHeader(Map*);
void saveMapConnections(Map*);
void updateMapsWithConnections(Map*);
void saveMapsWithConnections();
void saveMapLayoutsTable();
void updateMapLayout(Map*);
void readCDefinesSorted(QString, QStringList, QStringList*);
void readCDefinesSorted(QString, QStringList, QStringList*, QString, int);
void setNewMapHeader(Map* map, int mapIndex);
void setNewMapLayout(Map* map);
void setNewMapBlockdata(Map* map);
void setNewMapBorder(Map *map);
void setNewMapEvents(Map *map);
void setNewMapConnections(Map *map);
static int num_tiles_primary;
static int num_tiles_total;
static int num_metatiles_primary;
static int num_metatiles_total;
static int num_pals_primary;
static int num_pals_total;
};
#endif // PROJECT_H
#ifndef PROJECT_H
#define PROJECT_H
#include "map.h"
#include "blockdata.h"
#include "heallocation.h"
#include <QStringList>
#include <QList>
#include <QStandardItem>
static QString NONE_MAP_CONSTANT = "MAP_NONE";
static QString NONE_MAP_NAME = "None";
class Project
{
public:
Project();
QString root;
QStringList *groupNames = nullptr;
QMap<QString, int> *map_groups;
QList<QStringList> groupedMapNames;
QStringList *mapNames = nullptr;
QList<HealLocation> flyableMaps;
QMap<QString, QString>* mapConstantsToMapNames;
QMap<QString, QString>* mapNamesToMapConstants;
QList<QString> mapLayoutsTable;
QList<QString> mapLayoutsTableMaster;
QMap<QString, MapLayout*> mapLayouts;
QMap<QString, MapLayout*> mapLayoutsMaster;
QStringList *regionMapSections = nullptr;
QStringList *itemNames = nullptr;
QStringList *flagNames = nullptr;
QStringList *varNames = nullptr;
QStringList *movementTypes = nullptr;
QStringList *mapTypes = nullptr;
QStringList *mapBattleScenes = nullptr;
QStringList *weatherNames = nullptr;
QStringList *coordEventWeatherNames = nullptr;
QStringList *secretBaseIds = nullptr;
QStringList *bgEventFacingDirections = nullptr;
QStringList mapsWithConnections;
QMap<QString, int> metatileBehaviorMap;
QMap<int, QString> metatileBehaviorMapInverse;
QMap<QString, Map*> *map_cache;
Map* loadMap(QString);
Map* getMap(QString);
QMap<QString, Tileset*> *tileset_cache = nullptr;
Tileset* loadTileset(QString, Tileset *tileset = nullptr);
Tileset* getTileset(QString, bool forceLoad = false);
Blockdata* readBlockdata(QString);
void loadBlockdata(Map*);
QString readTextFile(QString path);
void saveTextFile(QString path, QString text);
void appendTextFile(QString path, QString text);
void deleteFile(QString path);
void readMapGroups();
Map* addNewMapToGroup(QString mapName, int groupNum);
QString getNewMapName();
QString getProjectTitle();
QList<QStringList>* getLabelMacros(QList<QStringList>*, QString);
QStringList* getLabelValues(QList<QStringList>*, QString);
void readMapHeader(Map*);
void readMapLayoutsTable();
void readAllMapLayouts();
QStringList* readLayoutValues(QString layoutName);
void readMapLayout(Map*);
void readMapsWithConnections();
void loadMapTilesets(Map*);
void loadTilesetAssets(Tileset*);
void loadTilesetTiles(Tileset*, QImage);
void loadTilesetMetatiles(Tileset*);
void saveBlockdata(Map*);
void saveMapBorder(Map*);
void writeBlockdata(QString, Blockdata*);
void saveAllMaps();
void saveMap(Map*);
void saveAllDataStructures();
void saveAllMapLayouts();
void saveMapGroupsTable();
void saveMapConstantsHeader();
void saveHealLocationStruct(Map*);
void saveTilesets(Tileset*, Tileset*);
QList<QStringList>* parseAsm(QString text);
QStringList getSongNames();
QStringList getVisibilities();
QMap<QString, QStringList> getTilesets();
void readTilesetProperties();
void readRegionMapSections();
void readItemNames();
void readFlagNames();
void readVarNames();
void readMovementTypes();
void readMapTypes();
void readMapBattleScenes();
void readWeatherNames();
void readCoordEventWeatherNames();
void readSecretBaseIds();
void readBgEventFacingDirections();
void readMetatileBehaviors();
void loadEventPixmaps(QList<Event*> objects);
QMap<QString, int> getEventObjGfxConstants();
QString fixPalettePath(QString path);
QString fixGraphicPath(QString path);
void readMapEvents(Map *map);
void loadMapConnections(Map *map);
void loadMapBorder(Map *map);
void saveMapEvents(Map *map);
QStringList readCArray(QString text, QString label);
QString readCIncbin(QString text, QString label);
QMap<QString, int> readCDefines(QString text, QStringList prefixes);
static int getNumTilesPrimary();
static int getNumTilesTotal();
static int getNumMetatilesPrimary();
static int getNumMetatilesTotal();
static int getNumPalettesPrimary();
static int getNumPalettesTotal();
private:
QString getMapLayoutsTableFilepath();
QString getMapLayoutFilepath(QString);
void saveMapHeader(Map*);
void saveMapConnections(Map*);
void saveTilesetMetatileAttributes(Tileset*);
void saveTilesetMetatiles(Tileset*);
void saveTilesetTilesImage(Tileset*);
void saveTilesetPalettes(Tileset*, bool);
void updateMapsWithConnections(Map*);
void saveMapsWithConnections();
void saveMapLayoutsTable();
void updateMapLayout(Map*);
void readCDefinesSorted(QString, QStringList, QStringList*);
void readCDefinesSorted(QString, QStringList, QStringList*, QString, int);
void setNewMapHeader(Map* map, int mapIndex);
void setNewMapLayout(Map* map);
void setNewMapBlockdata(Map* map);
void setNewMapBorder(Map *map);
void setNewMapEvents(Map *map);
void setNewMapConnections(Map *map);
static int num_tiles_primary;
static int num_tiles_total;
static int num_metatiles_primary;
static int num_metatiles_total;
static int num_pals_primary;
static int num_pals_total;
};
#endif // PROJECT_H

15
include/settings.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QCursor>
class Settings
{
public:
Settings();
bool smartPathsEnabled;
bool betterCursors;
QCursor mapCursor;
};
#endif // SETTINGS_H

View file

@ -0,0 +1,25 @@
#ifndef BORDERMETATILESPIXMAPITEM_H
#define BORDERMETATILESPIXMAPITEM_H
#include "map.h"
#include "metatileselector.h"
#include <QGraphicsPixmapItem>
class BorderMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
BorderMetatilesPixmapItem(Map *map_, MetatileSelector *metatileSelector) {
this->map = map_;
this->metatileSelector = metatileSelector;
setAcceptHoverEvents(true);
}
MetatileSelector *metatileSelector;
Map* map;
void draw();
signals:
void borderMetatilesChanged();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
};
#endif // BORDERMETATILESPIXMAPITEM_H

View file

@ -0,0 +1,37 @@
#ifndef COLLISIONPIXMAPITEM_H
#define COLLISIONPIXMAPITEM_H
#include "metatileselector.h"
#include "movementpermissionsselector.h"
#include "mappixmapitem.h"
#include "map.h"
#include "settings.h"
class CollisionPixmapItem : public MapPixmapItem {
Q_OBJECT
public:
CollisionPixmapItem(Map *map, MovementPermissionsSelector *movementPermissionsSelector, MetatileSelector *metatileSelector, Settings *settings)
: MapPixmapItem(map, metatileSelector, settings){
this->movementPermissionsSelector = movementPermissionsSelector;
}
MovementPermissionsSelector *movementPermissionsSelector;
void updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event);
virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*);
virtual void pick(QGraphicsSceneMouseEvent*);
virtual void draw(bool ignoreCache = false);
signals:
void mouseEvent(QGraphicsSceneMouseEvent *, CollisionPixmapItem *);
void hoveredMapMovementPermissionChanged(int, int);
void hoveredMapMovementPermissionCleared();
protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
};
#endif // COLLISIONPIXMAPITEM_H

View file

@ -0,0 +1,44 @@
#ifndef CONNECTIONPIXMAPITEM_H
#define CONNECTIONPIXMAPITEM_H
#include "mapconnection.h"
#include <QGraphicsPixmapItem>
#include <QPainter>
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
ConnectionPixmapItem(QPixmap pixmap, MapConnection* connection, int x, int y, int baseMapWidth, int baseMapHeight): QGraphicsPixmapItem(pixmap) {
this->basePixmap = pixmap;
this->connection = connection;
setFlag(ItemIsMovable);
setFlag(ItemSendsGeometryChanges);
this->initialX = x;
this->initialY = y;
this->initialOffset = connection->offset.toInt();
this->baseMapWidth = baseMapWidth;
this->baseMapHeight = baseMapHeight;
}
QPixmap basePixmap;
MapConnection* connection;
int initialX;
int initialY;
int initialOffset;
int baseMapWidth;
int baseMapHeight;
void render(qreal opacity = 1);
int getMinOffset();
int getMaxOffset();
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
signals:
void connectionItemSelected(ConnectionPixmapItem* connectionItem);
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
void connectionMoved(MapConnection*);
};
#endif // CONNECTIONPIXMAPITEM_H

View file

@ -0,0 +1,20 @@
#ifndef CURRENTSELECTEDMETATILESPIXMAPITEM_H
#define CURRENTSELECTEDMETATILESPIXMAPITEM_H
#include "map.h"
#include "metatileselector.h"
#include <QGraphicsPixmapItem>
class CurrentSelectedMetatilesPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
CurrentSelectedMetatilesPixmapItem(Map *map, MetatileSelector *metatileSelector) {
this->map = map;
this->metatileSelector = metatileSelector;
}
Map* map = nullptr;
MetatileSelector *metatileSelector;
void draw();
};
#endif // CURRENTSELECTEDMETATILESPIXMAPITEM_H

View file

@ -0,0 +1,22 @@
#ifndef EVENTPROPERTIESFRAME_H
#define EVENTPROPERTIESFRAME_H
#include <QFrame>
namespace Ui {
class EventPropertiesFrame;
}
class EventPropertiesFrame : public QFrame
{
Q_OBJECT
public:
explicit EventPropertiesFrame(QWidget *parent = nullptr);
~EventPropertiesFrame();
public:
Ui::EventPropertiesFrame *ui;
};
#endif // EVENTPROPERTIESFRAME_H

52
graphicsview.h → include/ui/graphicsview.h Executable file → Normal file
View file

@ -1,26 +1,26 @@
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
class Editor;
class GraphicsView : public QGraphicsView
{
public:
GraphicsView() : QGraphicsView() {}
GraphicsView(QWidget *parent) : QGraphicsView(parent) {}
public:
// GraphicsView_Object object;
Editor *editor;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
};
//Q_DECLARE_METATYPE(GraphicsView)
#endif // GRAPHICSVIEW_H
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
class Editor;
class GraphicsView : public QGraphicsView
{
public:
GraphicsView() : QGraphicsView() {}
GraphicsView(QWidget *parent) : QGraphicsView(parent) {}
public:
// GraphicsView_Object object;
Editor *editor;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
};
//Q_DECLARE_METATYPE(GraphicsView)
#endif // GRAPHICSVIEW_H

View file

@ -0,0 +1,15 @@
#ifndef IMAGEPROVIDERS_H
#define IMAGEPROVIDERS_H
#include "block.h"
#include "tileset.h"
#include <QImage>
#include <QPixmap>
QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*);
QImage getTileImage(uint16_t, Tileset*, Tileset*);
QImage getColoredTileImage(uint16_t, Tileset*, Tileset*, int);
#endif // IMAGEPROVIDERS_H

View file

@ -0,0 +1,55 @@
#ifndef MAPPIXMAPITEM_H
#define MAPPIXMAPITEM_H
#include "map.h"
#include "settings.h"
#include "metatileselector.h"
#include <QGraphicsPixmapItem>
class MapPixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
MapPixmapItem(Map *map_, MetatileSelector *metatileSelector, Settings *settings) {
this->map = map_;
this->metatileSelector = metatileSelector;
this->settings = settings;
setAcceptHoverEvents(true);
}
Map *map;
MetatileSelector *metatileSelector;
Settings *settings;
bool active;
bool right_click;
int paint_tile_initial_x;
int paint_tile_initial_y;
QPoint selection_origin;
QList<QPoint> selection;
virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*);
void _floodFill(int x, int y);
void _floodFillSmartPath(int initialX, int initialY);
virtual void pick(QGraphicsSceneMouseEvent*);
virtual void select(QGraphicsSceneMouseEvent*);
virtual void shift(QGraphicsSceneMouseEvent*);
virtual void draw(bool ignoreCache = false);
void updateMetatileSelection(QGraphicsSceneMouseEvent *event);
private:
void paintNormal(int x, int y);
void paintSmartPath(int x, int y);
static QList<int> smartPathTable;
signals:
void mouseEvent(QGraphicsSceneMouseEvent *, MapPixmapItem *);
void hoveredMapMetatileChanged(int x, int y);
void hoveredMapMetatileCleared();
protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
};
#endif // MAPPIXMAPITEM_H

View file

@ -0,0 +1,19 @@
#ifndef MAPSCENEEVENTFILTER_H
#define MAPSCENEEVENTFILTER_H
#include <QObject>
class MapSceneEventFilter : public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
public:
explicit MapSceneEventFilter(QObject *parent = nullptr);
signals:
void wheelZoom(int delta);
public slots:
};
#endif // MAPSCENEEVENTFILTER_H

View file

@ -0,0 +1,29 @@
#ifndef METATILELAYERSITEM_H
#define METATILELAYERSITEM_H
#include "tileset.h"
#include <QGraphicsPixmapItem>
#include <QGraphicsSceneMouseEvent>
class MetatileLayersItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset) {
this->metatile = metatile;
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
}
void draw();
void setTilesets(Tileset*, Tileset*);
void setMetatile(Metatile*);
private:
Metatile* metatile;
Tileset *primaryTileset;
Tileset *secondaryTileset;
signals:
void tileChanged(int, int);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
};
#endif // METATILELAYERSITEM_H

View file

@ -0,0 +1,51 @@
#ifndef METATILESELECTOR_H
#define METATILESELECTOR_H
#include "selectablepixmapitem.h"
#include "tileset.h"
class MetatileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
MetatileSelector(int numMetatilesWide, Tileset *primaryTileset, Tileset *secondaryTileset): SelectablePixmapItem(16, 16) {
this->externalSelection = false;
this->numMetatilesWide = numMetatilesWide;
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->selectedMetatiles = new QList<uint16_t>();
this->externalSelectedMetatiles = new QList<uint16_t>();
setAcceptHoverEvents(true);
}
QPoint getSelectionDimensions();
void draw();
void select(uint16_t metatile);
void setTilesets(Tileset*, Tileset*);
QList<uint16_t>* getSelectedMetatiles();
void setExternalSelection(int, int, QList<uint16_t>*);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
private:
bool externalSelection;
int numMetatilesWide;
Tileset *primaryTileset;
Tileset *secondaryTileset;
QList<uint16_t> *selectedMetatiles;
int externalSelectionWidth;
int externalSelectionHeight;
QList<uint16_t> *externalSelectedMetatiles;
void updateSelectedMetatiles();
uint16_t getMetatileId(int x, int y);
QPoint getMetatileIdCoords(uint16_t);
signals:
void hoveredMetatileSelectionChanged(uint16_t);
void hoveredMetatileSelectionCleared();
void selectedMetatilesChanged();
};
#endif // METATILESELECTOR_H

View file

@ -0,0 +1,29 @@
#ifndef MOVEMENTPERMISSIONSSELECTOR_H
#define MOVEMENTPERMISSIONSSELECTOR_H
#include "selectablepixmapitem.h"
class MovementPermissionsSelector: public SelectablePixmapItem {
Q_OBJECT
public:
MovementPermissionsSelector(): SelectablePixmapItem(32, 32, 1, 1) {
setAcceptHoverEvents(true);
}
void draw();
uint16_t getSelectedCollision();
uint16_t getSelectedElevation();
void select(uint16_t collision, uint16_t elevation);
protected:
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
private:
void setSelectedMovementPermissions(QPointF);
signals:
void hoveredMovementPermissionChanged(uint16_t, uint16_t);
void hoveredMovementPermissionCleared();
};
#endif // MOVEMENTPERMISSIONSSELECTOR_H

View file

@ -9,7 +9,6 @@ class NewEventToolButton : public QToolButton
Q_OBJECT
public:
explicit NewEventToolButton(QWidget *parent = nullptr);
void initButton();
QString getSelectedEventType();
public slots:
void newObject();
@ -32,6 +31,7 @@ private:
QAction *newSignAction;
QAction *newHiddenItemAction;
QAction *newSecretBaseAction;
void init();
};
#endif // NEWEVENTTOOLBUTTON_H

View file

@ -0,0 +1,43 @@
#ifndef PALETTEEDITOR_H
#define PALETTEEDITOR_H
#include <QMainWindow>
#include <QSlider>
#include <QFrame>
#include "project.h"
namespace Ui {
class PaletteEditor;
}
class PaletteEditor : public QMainWindow {
Q_OBJECT
public:
explicit PaletteEditor(Project*, Tileset*, Tileset*, QWidget *parent = nullptr);
~PaletteEditor();
void setPaletteId(int);
private:
Ui::PaletteEditor *ui;
Project *project = nullptr;
QList<QList<QSlider*>> sliders;
QList<QFrame*> frames;
Tileset *primaryTileset;
Tileset *secondaryTileset;
void disableSliderSignals();
void enableSliderSignals();
void initColorSliders();
void refreshColorSliders();
void refreshColors();
void refreshColor(int);
void setColor(int);
signals:
void closed();
void changedPaletteColor();
void changedPalette(int);
private slots:
void on_spinBox_PaletteId_valueChanged(int arg1);
};
#endif // PALETTEEDITOR_H

View file

@ -0,0 +1,40 @@
#ifndef SELECTABLEPIXMAPITEM_H
#define SELECTABLEPIXMAPITEM_H
#include <QGraphicsPixmapItem>
#include <QGraphicsSceneMouseEvent>
class SelectablePixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
SelectablePixmapItem(int cellWidth, int cellHeight): SelectablePixmapItem(cellWidth, cellHeight, INT_MAX, INT_MAX) {}
SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth, int maxSelectionHeight) {
this->cellWidth = cellWidth;
this->cellHeight = cellHeight;
this->maxSelectionWidth = maxSelectionWidth;
this->maxSelectionHeight = maxSelectionHeight;
}
virtual QPoint getSelectionDimensions();
virtual void draw() = 0;
protected:
int cellWidth;
int cellHeight;
int maxSelectionWidth;
int maxSelectionHeight;
int selectionInitialX;
int selectionInitialY;
int selectionOffsetX;
int selectionOffsetY;
QPoint getSelectionStart();
void select(int, int, int, int);
void updateSelection(int, int);
QPoint getCellPos(QPointF);
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
virtual void drawSelection();
};
#endif // SELECTABLEPIXMAPITEM_H

View file

@ -0,0 +1,90 @@
#ifndef TILESETEDITOR_H
#define TILESETEDITOR_H
#include <QMainWindow>
#include "project.h"
#include "paletteeditor.h"
#include "tileseteditormetatileselector.h"
#include "tileseteditortileselector.h"
#include "metatilelayersitem.h"
namespace Ui {
class TilesetEditor;
}
class TilesetEditor : public QMainWindow
{
Q_OBJECT
public:
explicit TilesetEditor(Project*, QString, QString, QWidget *parent = nullptr);
~TilesetEditor();
void setTilesets(QString, QString);
void init(Project*, QString, QString);
private slots:
void onHoveredMetatileChanged(uint16_t);
void onHoveredMetatileCleared();
void onSelectedMetatileChanged(uint16_t);
void onHoveredTileChanged(uint16_t);
void onHoveredTileCleared();
void onSelectedTilesChanged();
void onMetatileLayerTileChanged(int, int);
void onPaletteEditorClosed();
void onPaletteEditorChangedPaletteColor();
void onPaletteEditorChangedPalette(int);
void on_spinBox_paletteSelector_valueChanged(int arg1);
void on_checkBox_xFlip_stateChanged(int arg1);
void on_checkBox_yFlip_stateChanged(int arg1);
void on_comboBox_metatileBehaviors_currentIndexChanged(const QString &arg1);
void on_comboBox_layerType_currentIndexChanged(int index);
void on_actionSave_Tileset_triggered();
void on_actionImport_Primary_Tiles_triggered();
void on_actionImport_Secondary_Tiles_triggered();
void on_actionChange_Metatiles_Count_triggered();
void on_actionChange_Palettes_triggered();
private:
void closeEvent(QCloseEvent*);
void initMetatileSelector();
void initTileSelector();
void initSelectedTileItem();
void initMetatileLayersItem();
void drawSelectedTiles();
void importTilesetTiles(Tileset*, bool);
void refresh();
Ui::TilesetEditor *ui;
TilesetEditorMetatileSelector *metatileSelector = nullptr;
TilesetEditorTileSelector *tileSelector = nullptr;
MetatileLayersItem *metatileLayersItem = nullptr;
PaletteEditor *paletteEditor = nullptr;
Project *project = nullptr;
Metatile *metatile = nullptr;
int paletteId;
bool tileXFlip;
bool tileYFlip;
bool hasUnsavedChanges;
Tileset *primaryTileset = nullptr;
Tileset *secondaryTileset = nullptr;
QGraphicsScene *metatilesScene = nullptr;
QGraphicsScene *tilesScene = nullptr;
QGraphicsScene *selectedTileScene = nullptr;
QGraphicsPixmapItem *selectedTilePixmapItem = nullptr;
QGraphicsScene *metatileLayersScene = nullptr;
signals:
void tilesetsSaved(QString, QString);
void closed();
};
#endif // TILESETEDITOR_H

View file

@ -0,0 +1,44 @@
#ifndef TILESETEDITORMETATILESELECTOR_H
#define TILESETEDITORMETATILESELECTOR_H
#include "selectablepixmapitem.h"
#include "tileset.h"
class TilesetEditorMetatileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
TilesetEditorMetatileSelector(Tileset *primaryTileset, Tileset *secondaryTileset): SelectablePixmapItem(32, 32, 1, 1) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->numMetatilesWide = 8;
setAcceptHoverEvents(true);
}
void draw();
void select(uint16_t metatileId);
void setTilesets(Tileset*, Tileset*);
uint16_t getSelectedMetatile();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
private:
Tileset *primaryTileset = nullptr;
Tileset *secondaryTileset = nullptr;
uint16_t selectedMetatile;
int numMetatilesWide;
void updateSelectedMetatile();
uint16_t getMetatileId(int x, int y);
QPoint getMetatileIdCoords(uint16_t);
uint16_t getValidMetatileId(uint16_t);
signals:
void hoveredMetatileChanged(uint16_t);
void hoveredMetatileCleared();
void selectedMetatileChanged(uint16_t);
};
#endif // TILESETEDITORMETATILESELECTOR_H

View file

@ -0,0 +1,52 @@
#ifndef TILESETEDITORTILESELECTOR_H
#define TILESETEDITORTILESELECTOR_H
#include "selectablepixmapitem.h"
#include "tileset.h"
class TilesetEditorTileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset): SelectablePixmapItem(16, 16, 2, 2) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->numTilesWide = 16;
this->paletteId = 0;
this->xFlip = false;
this->yFlip = false;
setAcceptHoverEvents(true);
}
void draw();
void select(uint16_t metatileId);
void setTilesets(Tileset*, Tileset*);
void setPaletteId(int);
void setTileFlips(bool, bool);
QList<uint16_t> getSelectedTiles();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void hoverMoveEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
private:
Tileset *primaryTileset;
Tileset *secondaryTileset;
QList<uint16_t> selectedTiles;
int numTilesWide;
int paletteId;
bool xFlip;
bool yFlip;
void updateSelectedTiles();
uint16_t getTileId(int x, int y);
QPoint getTileCoords(uint16_t);
QList<QRgb> getCurPaletteTable();
signals:
void hoveredTileChanged(uint16_t);
void hoveredTileCleared();
void selectedTilesChanged();
};
#endif // TILESETEDITORTILESELECTOR_H

236
map.h
View file

@ -1,236 +0,0 @@
#ifndef MAP_H
#define MAP_H
#include "tileset.h"
#include "blockdata.h"
#include "event.h"
#include <QPixmap>
#include <QObject>
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <math.h>
class HistoryItem {
public:
Blockdata *metatiles;
int layoutWidth;
int layoutHeight;
HistoryItem(Blockdata *metatiles_, int layoutWidth_, int layoutHeight_) {
this->metatiles = metatiles_;
this->layoutWidth = layoutWidth_;
this->layoutHeight = layoutHeight_;
}
~HistoryItem() {
if (metatiles) delete metatiles;
}
};
template <typename T>
class History {
public:
History() {
}
T back() {
if (head > 0) {
return history.at(--head);
}
return NULL;
}
T next() {
if (head + 1 < history.length()) {
return history.at(++head);
}
return NULL;
}
void push(T commit) {
while (head + 1 < history.length()) {
HistoryItem *item = history.last();
history.removeLast();
delete item;
}
if (saved > head) {
saved = -1;
}
history.append(commit);
head++;
}
T current() {
if (head < 0 || history.length() == 0) {
return NULL;
}
return history.at(head);
}
void save() {
saved = head;
}
bool isSaved() {
return saved == head;
}
private:
QList<T> history;
int head = -1;
int saved = -1;
};
class Connection {
public:
Connection() {
}
public:
QString direction;
QString offset;
QString map_name;
};
class MapLayout {
public:
MapLayout() {}
int index;
QString name;
QString label;
QString width;
QString height;
QString border_label;
QString border_path;
QString blockdata_label;
QString blockdata_path;
QString tileset_primary_label;
QString tileset_secondary_label;
Tileset *tileset_primary = nullptr;
Tileset *tileset_secondary = nullptr;
Blockdata* blockdata = nullptr;
QImage border_image;
QPixmap border_pixmap;
Blockdata *border = nullptr;
Blockdata *cached_blockdata = nullptr;
Blockdata *cached_collision = nullptr;
Blockdata *cached_border = nullptr;
bool has_unsaved_changes = false;
public:
static QString getNameFromLabel(QString label) {
// ASSUMPTION: strip off "_Layout" from layout label. Directories in 'data/layouts/' must be well-formed.
return label.replace(label.lastIndexOf("_Layout"), label.length(), "");
}
};
class Map : public QObject
{
Q_OBJECT
public:
explicit Map(QObject *parent = nullptr);
public:
QString name;
QString constantName;
QString group_num;
QString layout_label;
QString events_label;
QString scripts_label;
QString connections_label;
QString song;
QString layout_id;
QString location;
QString requiresFlash;
QString isFlyable; // TODO: implement this
QString weather;
QString type;
QString unknown;
QString show_location;
QString battle_scene;
MapLayout *layout;
int scale_exp = 0;
double scale_base = sqrt(2); // adjust scale factor with this
bool isPersistedToFile = true;
public:
void setName(QString mapName);
static QString mapConstantFromName(QString mapName);
static QString objectEventsLabelFromName(QString mapName);
static QString warpEventsLabelFromName(QString mapName);
static QString coordEventsLabelFromName(QString mapName);
static QString bgEventsLabelFromName(QString mapName);
int getWidth();
int getHeight();
uint16_t getSelectedBlockIndex(int);
int getDisplayedBlockIndex(int);
QPixmap render(bool ignoreCache);
QPixmap renderMetatiles();
QPixmap renderCollision(bool ignoreCache);
QImage collision_image;
QPixmap collision_pixmap;
QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
QPixmap renderCollisionMetatiles();
void drawSelection(int i, int w, int selectionWidth, int selectionHeight, QPainter *painter, int gridWidth);
bool blockChanged(int, Blockdata*);
void cacheBlockdata();
void cacheCollision();
QImage image;
QPixmap pixmap;
QList<QImage> metatile_images;
bool smart_paths_enabled = false;
int paint_metatile_initial_x;
int paint_metatile_initial_y;
int paint_tile_index;
int paint_tile_width = 1;
int paint_tile_height = 1;
int paint_tile_initial_x;
int paint_tile_initial_y;
int selected_metatiles_width;
int selected_metatiles_height;
QList<uint16_t> *selected_metatiles = nullptr;
uint16_t paint_collision;
uint16_t paint_elevation;
Block *getBlock(int x, int y);
void setBlock(int x, int y, Block block);
void _setBlock(int x, int y, Block block);
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
History<HistoryItem*> history;
void undo();
void redo();
void commit();
QList<Event*> getAllEvents();
void removeEvent(Event *event);
void addEvent(Event *event);
QMap<QString, QList<Event*>> events;
QList<Connection*> connections;
QPixmap renderConnection(Connection);
void setNewDimensionsBlockdata(int newWidth, int newHeight);
void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true);
QPixmap renderBorder();
void cacheBorder();
bool hasUnsavedChanges();
void hoveredTileChanged(int x, int y, int block);
void clearHoveredTile();
void hoveredMetatileChanged(int block);
void clearHoveredMetatile();
void hoveredMovementPermissionTileChanged(int collision, int elevation);
void clearHoveredMovementPermissionTile();
void setSelectedMetatilesFromTilePicker();
signals:
void paintTileChanged();
void paintCollisionChanged(Map *map);
void mapChanged(Map *map);
void mapNeedsRedrawing();
void statusBarMessage(QString);
public slots:
};
#endif // MAP_H

View file

@ -1,14 +0,0 @@
#include "objectpropertiesframe.h"
#include "ui_objectpropertiesframe.h"
ObjectPropertiesFrame::ObjectPropertiesFrame(QWidget *parent) :
QFrame(parent),
ui(new Ui::ObjectPropertiesFrame)
{
ui->setupUi(this);
}
ObjectPropertiesFrame::~ObjectPropertiesFrame()
{
delete ui;
}

View file

@ -1,22 +0,0 @@
#ifndef OBJECTPROPERTIESFRAME_H
#define OBJECTPROPERTIESFRAME_H
#include <QFrame>
namespace Ui {
class ObjectPropertiesFrame;
}
class ObjectPropertiesFrame : public QFrame
{
Q_OBJECT
public:
explicit ObjectPropertiesFrame(QWidget *parent = nullptr);
~ObjectPropertiesFrame();
public:
Ui::ObjectPropertiesFrame *ui;
};
#endif // OBJECTPROPERTIESFRAME_H

116
porymap.pro Executable file → Normal file
View file

@ -14,43 +14,89 @@ RC_ICONS = resources/icons/porymap-icon-1.ico
ICON = resources/icons/porymap-icon-1.ico
SOURCES += main.cpp\
mainwindow.cpp \
project.cpp \
map.cpp \
blockdata.cpp \
block.cpp \
tileset.cpp \
tile.cpp \
event.cpp \
editor.cpp \
objectpropertiesframe.cpp \
graphicsview.cpp \
parseutil.cpp \
neweventtoolbutton.cpp \
noscrollcombobox.cpp \
noscrollspinbox.cpp \
heallocation.cpp
SOURCES += src/core/block.cpp \
src/core/blockdata.cpp \
src/core/event.cpp \
src/core/heallocation.cpp \
src/core/historyitem.cpp \
src/core/map.cpp \
src/core/maplayout.cpp \
src/core/metatile.cpp \
src/core/parseutil.cpp \
src/core/tile.cpp \
src/core/tileset.cpp \
src/ui/bordermetatilespixmapitem.cpp \
src/ui/collisionpixmapitem.cpp \
src/ui/connectionpixmapitem.cpp \
src/ui/currentselectedmetatilespixmapitem.cpp \
src/ui/eventpropertiesframe.cpp \
src/ui/graphicsview.cpp \
src/ui/imageproviders.cpp \
src/ui/mappixmapitem.cpp \
src/ui/mapsceneeventfilter.cpp \
src/ui/metatilelayersitem.cpp \
src/ui/metatileselector.cpp \
src/ui/movementpermissionsselector.cpp \
src/ui/neweventtoolbutton.cpp \
src/ui/noscrollcombobox.cpp \
src/ui/noscrollspinbox.cpp \
src/ui/paletteeditor.cpp \
src/ui/selectablepixmapitem.cpp \
src/ui/tileseteditor.cpp \
src/ui/tileseteditormetatileselector.cpp \
src/ui/tileseteditortileselector.cpp \
src/editor.cpp \
src/main.cpp \
src/mainwindow.cpp \
src/project.cpp \
src/settings.cpp
HEADERS += mainwindow.h \
project.h \
map.h \
blockdata.h \
block.h \
tileset.h \
tile.h \
event.h \
editor.h \
objectpropertiesframe.h \
graphicsview.h \
parseutil.h \
neweventtoolbutton.h \
noscrollcombobox.h \
noscrollspinbox.h \
heallocation.h
HEADERS += include/core/block.h \
include/core/blockdata.h \
include/core/event.h \
include/core/heallocation.h \
include/core/history.h \
include/core/historyitem.h \
include/core/map.h \
include/core/mapconnection.h \
include/core/maplayout.h \
include/core/metatile.h \
include/core/parseutil.h \
include/core/tile.h \
include/core/tileset.h \
include/ui/bordermetatilespixmapitem.h \
include/ui/collisionpixmapitem.h \
include/ui/connectionpixmapitem.h \
include/ui/currentselectedmetatilespixmapitem.h \
include/ui/eventpropertiesframe.h \
include/ui/graphicsview.h \
include/ui/imageproviders.h \
include/ui/mappixmapitem.h \
include/ui/mapsceneeventfilter.h \
include/ui/metatilelayersitem.h \
include/ui/metatileselector.h \
include/ui/movementpermissionsselector.h \
include/ui/neweventtoolbutton.h \
include/ui/noscrollcombobox.h \
include/ui/noscrollspinbox.h \
include/ui/paletteeditor.h \
include/ui/selectablepixmapitem.h \
include/ui/tileseteditor.h \
include/ui/tileseteditormetatileselector.h \
include/ui/tileseteditortileselector.h \
include/editor.h \
include/mainwindow.h \
include/project.h \
include/settings.h
FORMS += mainwindow.ui \
objectpropertiesframe.ui
FORMS += forms/mainwindow.ui \
forms/eventpropertiesframe.ui \
forms/tileseteditor.ui \
forms/paletteeditor.ui
RESOURCES += \
resources/images.qrc
INCLUDEPATH += include
INCLUDEPATH += include/core
INCLUDEPATH += include/ui

0
resources/icons/add.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/cursor.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/delete.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/fill_color.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/folder.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/folder_closed.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/folder_closed_map.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/folder_image.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/folder_map.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
resources/icons/image.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/map.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/pencil.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/pipette.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
resources/icons/viewsprites.ico Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

54
resources/images.qrc Executable file → Normal file
View file

@ -1,27 +1,27 @@
<RCC>
<qresource prefix="/">
<file>icons/folder.ico</file>
<file>icons/folder_closed.ico</file>
<file>icons/folder_closed_map.ico</file>
<file>icons/folder_image.ico</file>
<file>icons/folder_map.ico</file>
<file>icons/image.ico</file>
<file>icons/map.ico</file>
<file>icons/cursor.ico</file>
<file>icons/fill_color.ico</file>
<file>icons/move.ico</file>
<file>icons/pencil.ico</file>
<file>icons/pipette.ico</file>
<file>images/Entities_16x16.png</file>
<file>icons/add.ico</file>
<file>icons/delete.ico</file>
<file>icons/viewsprites.ico</file>
<file>images/collisions.png</file>
<file>icons/fill_color_cursor.ico</file>
<file>icons/pencil_cursor.ico</file>
<file>icons/pipette_cursor.ico</file>
<file>icons/shift.ico</file>
<file>icons/shift_cursor.ico</file>
<file>icons/porymap-icon-1.ico</file>
</qresource>
</RCC>
<RCC>
<qresource prefix="/">
<file>icons/folder.ico</file>
<file>icons/folder_closed.ico</file>
<file>icons/folder_closed_map.ico</file>
<file>icons/folder_image.ico</file>
<file>icons/folder_map.ico</file>
<file>icons/image.ico</file>
<file>icons/map.ico</file>
<file>icons/cursor.ico</file>
<file>icons/fill_color.ico</file>
<file>icons/move.ico</file>
<file>icons/pencil.ico</file>
<file>icons/pipette.ico</file>
<file>images/Entities_16x16.png</file>
<file>icons/add.ico</file>
<file>icons/delete.ico</file>
<file>icons/viewsprites.ico</file>
<file>images/collisions.png</file>
<file>icons/fill_color_cursor.ico</file>
<file>icons/pencil_cursor.ico</file>
<file>icons/pipette_cursor.ico</file>
<file>icons/shift.ico</file>
<file>icons/shift_cursor.ico</file>
<file>icons/porymap-icon-1.ico</file>
</qresource>
</RCC>

0
resources/images/Entities_16x16.png Executable file → Normal file
View file

Before

Width:  |  Height:  |  Size: 490 B

After

Width:  |  Height:  |  Size: 490 B

64
block.cpp → src/core/block.cpp Executable file → Normal file
View file

@ -1,32 +1,32 @@
#include "block.h"
Block::Block() {
}
Block::Block(uint16_t word)
{
tile = word & 0x3ff;
collision = (word >> 10) & 0x3;
elevation = (word >> 12) & 0xf;
}
Block::Block(const Block &block) {
tile = block.tile;
collision = block.collision;
elevation = block.elevation;
}
uint16_t Block::rawValue() {
return static_cast<uint16_t>(
(tile & 0x3ff) +
((collision & 0x3) << 10) +
((elevation & 0xf) << 12));
}
bool Block::operator ==(Block other) {
return (tile == other.tile) && (collision == other.collision) && (elevation == other.elevation);
}
bool Block::operator !=(Block other) {
return !(operator ==(other));
}
#include "block.h"
Block::Block() {
}
Block::Block(uint16_t word)
{
tile = word & 0x3ff;
collision = (word >> 10) & 0x3;
elevation = (word >> 12) & 0xf;
}
Block::Block(const Block &block) {
tile = block.tile;
collision = block.collision;
elevation = block.elevation;
}
uint16_t Block::rawValue() {
return static_cast<uint16_t>(
(tile & 0x3ff) +
((collision & 0x3) << 10) +
((elevation & 0xf) << 12));
}
bool Block::operator ==(Block other) {
return (tile == other.tile) && (collision == other.collision) && (elevation == other.elevation);
}
bool Block::operator !=(Block other) {
return !(operator ==(other));
}

109
blockdata.cpp → src/core/blockdata.cpp Executable file → Normal file
View file

@ -1,55 +1,54 @@
#include "blockdata.h"
#include <QDebug>
Blockdata::Blockdata(QObject *parent) : QObject(parent)
{
blocks = new QList<Block>;
}
void Blockdata::addBlock(uint16_t word) {
Block block(word);
blocks->append(block);
}
void Blockdata::addBlock(Block block) {
blocks->append(block);
}
QByteArray Blockdata::serialize() {
QByteArray data;
for (int i = 0; i < blocks->length(); i++) {
Block block = blocks->value(i);
uint16_t word = block.rawValue();
data.append(static_cast<char>(word & 0xff));
data.append(static_cast<char>((word >> 8) & 0xff));
}
return data;
}
void Blockdata::copyFrom(Blockdata* other) {
blocks->clear();
for (int i = 0; i < other->blocks->length(); i++) {
addBlock(other->blocks->value(i));
}
}
Blockdata* Blockdata::copy() {
Blockdata* blockdata = new Blockdata;
blockdata->copyFrom(this);
return blockdata;
}
bool Blockdata::equals(Blockdata *other) {
if (!other) {
return false;
}
if (blocks->length() != other->blocks->length()) {
return false;
}
for (int i = 0; i < blocks->length(); i++) {
if (blocks->value(i) != other->blocks->value(i)) {
return false;
}
}
return true;
}
#include "blockdata.h"
Blockdata::Blockdata(QObject *parent) : QObject(parent)
{
blocks = new QList<Block>;
}
void Blockdata::addBlock(uint16_t word) {
Block block(word);
blocks->append(block);
}
void Blockdata::addBlock(Block block) {
blocks->append(block);
}
QByteArray Blockdata::serialize() {
QByteArray data;
for (int i = 0; i < blocks->length(); i++) {
Block block = blocks->value(i);
uint16_t word = block.rawValue();
data.append(static_cast<char>(word & 0xff));
data.append(static_cast<char>((word >> 8) & 0xff));
}
return data;
}
void Blockdata::copyFrom(Blockdata* other) {
blocks->clear();
for (int i = 0; i < other->blocks->length(); i++) {
addBlock(other->blocks->value(i));
}
}
Blockdata* Blockdata::copy() {
Blockdata* blockdata = new Blockdata;
blockdata->copyFrom(this);
return blockdata;
}
bool Blockdata::equals(Blockdata *other) {
if (!other) {
return false;
}
if (blocks->length() != other->blocks->length()) {
return false;
}
for (int i = 0; i < blocks->length(); i++) {
if (blocks->value(i) != other->blocks->value(i)) {
return false;
}
}
return true;
}

505
event.cpp → src/core/event.cpp Executable file → Normal file
View file

@ -1,260 +1,245 @@
#include "event.h"
#include "map.h"
QString EventType::Object = "event_object";
QString EventType::Warp = "event_warp";
QString EventType::CoordScript = "event_trap";
QString EventType::CoordWeather = "event_trap_weather";
QString EventType::Sign = "event_sign";
QString EventType::HiddenItem = "event_hidden_item";
QString EventType::SecretBase = "event_secret_base";
QString EventType::HealLocation = "event_heal_location";
Event::Event()
{
this->spriteWidth = 16;
this->spriteHeight = 16;
}
Event* Event::createNewEvent(QString event_type, QString map_name)
{
Event *event = new Event;
if (event_type == EventType::Object) {
event = createNewObjectEvent();
} else if (event_type == EventType::Warp) {
event = createNewWarpEvent(map_name);
} else if (event_type == EventType::HealLocation) {
event = createNewHealLocationEvent(map_name);
} else if (event_type == EventType::CoordScript) {
event = createNewCoordScriptEvent();
} else if (event_type == EventType::CoordWeather) {
event = createNewCoordWeatherEvent();
} else if (event_type == EventType::Sign) {
event = createNewSignEvent();
} else if (event_type == EventType::HiddenItem) {
event = createNewHiddenItemEvent();
} else if (event_type == EventType::SecretBase) {
event = createNewSecretBaseEvent();
}
event->setX(0);
event->setY(0);
event->put("elevation", 3);
return event;
}
Event* Event::createNewObjectEvent()
{
Event *event = new Event;
event->put("event_group_type", "object_event_group");
event->put("event_type", EventType::Object);
event->put("sprite", "EVENT_OBJ_GFX_BOY_1");
event->put("movement_type", "MOVEMENT_TYPE_LOOK_AROUND");
event->put("radius_x", 0);
event->put("radius_y", 0);
event->put("script_label", "NULL");
event->put("event_flag", "0");
event->put("replacement", "0");
event->put("is_trainer", "FALSE");
event->put("sight_radius_tree_id", 0);
return event;
}
Event* Event::createNewWarpEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "warp_event_group");
event->put("event_type", EventType::Warp);
event->put("destination_warp", 0);
event->put("destination_map_name", map_name);
return event;
}
Event* Event::createNewHealLocationEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "heal_event_group");
event->put("event_type", EventType::HealLocation);
event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4));
return event;
}
Event* Event::createNewCoordScriptEvent()
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::CoordScript);
event->put("script_label", "NULL");
event->put("script_var", "VAR_TEMP_0");
event->put("script_var_value", "0");
return event;
}
Event* Event::createNewCoordWeatherEvent()
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::CoordWeather);
event->put("weather", "COORD_EVENT_WEATHER_SUNNY");
return event;
}
Event* Event::createNewSignEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::Sign);
event->put("player_facing_direction", "BG_EVENT_PLAYER_FACING_ANY");
event->put("script_label", "NULL");
return event;
}
Event* Event::createNewHiddenItemEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::HiddenItem);
event->put("item", "ITEM_POTION");
event->put("flag", "FLAG_HIDDEN_ITEM_0");
return event;
}
Event* Event::createNewSecretBaseEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::SecretBase);
event->put("secret_base_id", "SECRET_BASE_RED_CAVE2_1");
return event;
}
int Event::getPixelX()
{
return (this->x() * 16) - qMax(0, (this->spriteWidth - 16) / 2);
}
int Event::getPixelY()
{
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
}
QString Event::buildObjectEventMacro(int item_index)
{
int radius_x = this->getInt("radius_x");
int radius_y = this->getInt("radius_y");
uint16_t x = this->getU16("x");
uint16_t y = this->getU16("y");
QString text = "";
text += QString("\tobject_event %1").arg(item_index + 1);
text += QString(", %1").arg(this->get("sprite"));
text += QString(", %1").arg(this->get("replacement"));
text += QString(", %1").arg(x);
text += QString(", %1").arg(y);
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("movement_type"));
text += QString(", %1").arg(radius_x);
text += QString(", %1").arg(radius_y);
text += QString(", %1").arg(this->get("is_trainer"));
text += QString(", %1").arg(this->get("sight_radius_tree_id"));
text += QString(", %1").arg(this->get("script_label"));
text += QString(", %1").arg(this->get("event_flag"));
text += "\n";
return text;
}
QString Event::buildWarpEventMacro(QMap<QString, QString> *mapNamesToMapConstants)
{
QString text = "";
text += QString("\twarp_def %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("destination_warp"));
text += QString(", %1").arg(mapNamesToMapConstants->value(this->get("destination_map_name")));
text += "\n";
return text;
}
HealLocation Event::buildHealLocation()
{
HealLocation hl;
hl.name = this->get("loc_name");
try {
hl.index = this->get("index").toInt();
}
catch(...) {
hl.index = 0;
}
hl.x = this->getU16("x");
hl.y = this->getU16("y");
return hl;
}
QString Event::buildCoordScriptEventMacro()
{
QString text = "";
text += QString("\tcoord_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("script_var"));
text += QString(", %1").arg(this->get("script_var_value"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
}
QString Event::buildCoordWeatherEventMacro()
{
QString text = "";
text += QString("\tcoord_weather_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("weather"));
text += "\n";
return text;
}
QString Event::buildSignEventMacro()
{
QString text = "";
text += QString("\tbg_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("player_facing_direction"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
}
QString Event::buildHiddenItemEventMacro()
{
QString text = "";
text += QString("\tbg_hidden_item_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("item"));
text += QString(", %1").arg(this->get("flag"));
text += "\n";
return text;
}
QString Event::buildSecretBaseEventMacro()
{
QString text = "";
text += QString("\tbg_secret_base_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("secret_base_id"));
text += "\n";
return text;
}
void Event::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight)
{
// Set first palette color fully transparent.
QImage img = spritesheet.copy(0, 0, spriteWidth, spriteHeight);
img.setColor(0, qRgba(0, 0, 0, 0));
pixmap = QPixmap::fromImage(img);
this->spriteWidth = spriteWidth;
this->spriteHeight = spriteHeight;
}
#include "event.h"
#include "map.h"
QString EventType::Object = "event_object";
QString EventType::Warp = "event_warp";
QString EventType::CoordScript = "event_trap";
QString EventType::CoordWeather = "event_trap_weather";
QString EventType::Sign = "event_sign";
QString EventType::HiddenItem = "event_hidden_item";
QString EventType::SecretBase = "event_secret_base";
QString EventType::HealLocation = "event_heal_location";
Event::Event()
{
this->spriteWidth = 16;
this->spriteHeight = 16;
}
Event* Event::createNewEvent(QString event_type, QString map_name)
{
Event *event = new Event;
if (event_type == EventType::Object) {
event = createNewObjectEvent();
} else if (event_type == EventType::Warp) {
event = createNewWarpEvent(map_name);
} else if (event_type == EventType::HealLocation) {
event = createNewHealLocationEvent(map_name);
} else if (event_type == EventType::CoordScript) {
event = createNewCoordScriptEvent();
} else if (event_type == EventType::CoordWeather) {
event = createNewCoordWeatherEvent();
} else if (event_type == EventType::Sign) {
event = createNewSignEvent();
} else if (event_type == EventType::HiddenItem) {
event = createNewHiddenItemEvent();
} else if (event_type == EventType::SecretBase) {
event = createNewSecretBaseEvent();
}
event->setX(0);
event->setY(0);
event->put("elevation", 3);
return event;
}
Event* Event::createNewObjectEvent()
{
Event *event = new Event;
event->put("event_group_type", "object_event_group");
event->put("event_type", EventType::Object);
event->put("sprite", "EVENT_OBJ_GFX_BOY_1");
event->put("movement_type", "MOVEMENT_TYPE_LOOK_AROUND");
event->put("radius_x", 0);
event->put("radius_y", 0);
event->put("script_label", "NULL");
event->put("event_flag", "0");
event->put("replacement", "0");
event->put("is_trainer", "FALSE");
event->put("sight_radius_tree_id", 0);
return event;
}
Event* Event::createNewWarpEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "warp_event_group");
event->put("event_type", EventType::Warp);
event->put("destination_warp", 0);
event->put("destination_map_name", map_name);
return event;
}
Event* Event::createNewHealLocationEvent(QString map_name)
{
Event *event = new Event;
event->put("event_group_type", "heal_event_group");
event->put("event_type", EventType::HealLocation);
event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4));
return event;
}
Event* Event::createNewCoordScriptEvent()
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::CoordScript);
event->put("script_label", "NULL");
event->put("script_var", "VAR_TEMP_0");
event->put("script_var_value", "0");
return event;
}
Event* Event::createNewCoordWeatherEvent()
{
Event *event = new Event;
event->put("event_group_type", "coord_event_group");
event->put("event_type", EventType::CoordWeather);
event->put("weather", "COORD_EVENT_WEATHER_SUNNY");
return event;
}
Event* Event::createNewSignEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::Sign);
event->put("player_facing_direction", "BG_EVENT_PLAYER_FACING_ANY");
event->put("script_label", "NULL");
return event;
}
Event* Event::createNewHiddenItemEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::HiddenItem);
event->put("item", "ITEM_POTION");
event->put("flag", "FLAG_HIDDEN_ITEM_0");
return event;
}
Event* Event::createNewSecretBaseEvent()
{
Event *event = new Event;
event->put("event_group_type", "bg_event_group");
event->put("event_type", EventType::SecretBase);
event->put("secret_base_id", "SECRET_BASE_RED_CAVE2_1");
return event;
}
int Event::getPixelX()
{
return (this->x() * 16) - qMax(0, (this->spriteWidth - 16) / 2);
}
int Event::getPixelY()
{
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
}
QString Event::buildObjectEventMacro(int item_index)
{
int radius_x = this->getInt("radius_x");
int radius_y = this->getInt("radius_y");
uint16_t x = this->getU16("x");
uint16_t y = this->getU16("y");
QString text = "";
text += QString("\tobject_event %1").arg(item_index + 1);
text += QString(", %1").arg(this->get("sprite"));
text += QString(", %1").arg(this->get("replacement"));
text += QString(", %1").arg(x);
text += QString(", %1").arg(y);
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("movement_type"));
text += QString(", %1").arg(radius_x);
text += QString(", %1").arg(radius_y);
text += QString(", %1").arg(this->get("is_trainer"));
text += QString(", %1").arg(this->get("sight_radius_tree_id"));
text += QString(", %1").arg(this->get("script_label"));
text += QString(", %1").arg(this->get("event_flag"));
text += "\n";
return text;
}
QString Event::buildWarpEventMacro(QMap<QString, QString> *mapNamesToMapConstants)
{
QString text = "";
text += QString("\twarp_def %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("destination_warp"));
text += QString(", %1").arg(mapNamesToMapConstants->value(this->get("destination_map_name")));
text += "\n";
return text;
}
QString Event::buildCoordScriptEventMacro()
{
QString text = "";
text += QString("\tcoord_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("script_var"));
text += QString(", %1").arg(this->get("script_var_value"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
}
QString Event::buildCoordWeatherEventMacro()
{
QString text = "";
text += QString("\tcoord_weather_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("weather"));
text += "\n";
return text;
}
QString Event::buildSignEventMacro()
{
QString text = "";
text += QString("\tbg_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("player_facing_direction"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
}
QString Event::buildHiddenItemEventMacro()
{
QString text = "";
text += QString("\tbg_hidden_item_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("item"));
text += QString(", %1").arg(this->get("flag"));
text += "\n";
return text;
}
QString Event::buildSecretBaseEventMacro()
{
QString text = "";
text += QString("\tbg_secret_base_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("secret_base_id"));
text += "\n";
return text;
}
void Event::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight)
{
// Set first palette color fully transparent.
QImage img = spritesheet.copy(0, 0, spriteWidth, spriteHeight);
img.setColor(0, qRgba(0, 0, 0, 0));
pixmap = QPixmap::fromImage(img);
this->spriteWidth = spriteWidth;
this->spriteHeight = spriteHeight;
}

View file

@ -8,6 +8,21 @@ HealLocation::HealLocation(QString map, int i, uint16_t x, uint16_t y)
this->y = y;
}
HealLocation HealLocation::fromEvent(Event *event)
{
HealLocation hl;
hl.name = event->get("loc_name");
try {
hl.index = event->get("index").toInt();
}
catch(...) {
hl.index = 0;
}
hl.x = event->getU16("x");
hl.y = event->getU16("y");
return hl;
}
QDebug operator<<(QDebug debug, const HealLocation &hl)
{
debug << "HealLocation_" + hl.name << "(" << hl.x << ',' << hl.y << ")";

4
src/core/history.cpp Normal file
View file

@ -0,0 +1,4 @@
#include "history.h"
#include "historyitem.h"

11
src/core/historyitem.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "historyitem.h"
HistoryItem::HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight) {
this->metatiles = metatiles;
this->layoutWidth = layoutWidth;
this->layoutHeight = layoutHeight;
}
HistoryItem::~HistoryItem() {
if (this->metatiles) delete this->metatiles;
}

1012
map.cpp → src/core/map.cpp Executable file → Normal file

File diff suppressed because it is too large Load diff

2
src/core/maplayout.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "maplayout.h"

27
src/core/metatile.cpp Normal file
View file

@ -0,0 +1,27 @@
#include "metatile.h"
#include "tileset.h"
#include "project.h"
Metatile::Metatile()
{
tiles = new QList<Tile>;
}
Metatile* Metatile::copy() {
Metatile *copy = new Metatile;
copy->behavior = this->behavior;
copy->layerType = this->layerType;
copy->tiles = new QList<Tile>;
for (Tile tile : *this->tiles) {
copy->tiles->append(tile);
}
return copy;
}
int Metatile::getBlockIndex(int index) {
if (index < Project::getNumMetatilesPrimary()) {
return index;
} else {
return index - Project::getNumMetatilesPrimary();
}
}

434
parseutil.cpp → src/core/parseutil.cpp Executable file → Normal file
View file

@ -1,217 +1,217 @@
#include "parseutil.h"
#include <QDebug>
#include <QRegularExpression>
#include <QStack>
ParseUtil::ParseUtil()
{
}
void ParseUtil::strip_comment(QString *line) {
bool in_string = false;
for (int i = 0; i < line->length(); i++) {
if (line->at(i) == '"') {
in_string = !in_string;
} else if (line->at(i) == '@') {
if (!in_string) {
line->truncate(i);
break;
}
}
}
}
QList<QStringList>* ParseUtil::parseAsm(QString text) {
QList<QStringList> *parsed = new QList<QStringList>;
QStringList lines = text.split('\n');
for (QString line : lines) {
QString label;
//QString macro;
//QStringList *params;
strip_comment(&line);
if (line.trimmed().isEmpty()) {
} else if (line.contains(':')) {
label = line.left(line.indexOf(':'));
QStringList *list = new QStringList;
list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
list->append(label);
parsed->append(*list);
// There should not be anything else on the line.
// gas will raise a syntax error if there is.
} else {
line = line.trimmed();
//parsed->append(line.split(QRegExp("\\s*,\\s*")));
QString macro;
QStringList params;
int index = line.indexOf(QRegExp("\\s+"));
macro = line.left(index);
params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
params.prepend(macro);
parsed->append(params);
}
//if (macro != NULL) {
// if (macros->contains(macro)) {
// void* function = macros->value(macro);
// if (function != NULL) {
// std::function function(params);
// }
// }
//}
}
return parsed;
}
int ParseUtil::evaluateDefine(QString define, QMap<QString, int>* knownDefines) {
QList<Token> tokens = tokenizeExpression(define, knownDefines);
QList<Token> postfixExpression = generatePostfix(tokens);
return evaluatePostfix(postfixExpression);
}
// arg here is the text in the file src/data/heal_locations.h
// returns a list of HealLocations (mapname, x, y)
QList<HealLocation>* ParseUtil::parseHealLocs(QString text) {
QList<HealLocation> *parsed = new QList<HealLocation>;
QStringList lines = text.split('\n');
int i = 1;
for (auto line : lines){
if (line.contains("MAP_GROUP")){
QList<QString> li = line.replace(" ","").chopped(2).remove('{').split(',');
HealLocation hloc = HealLocation(li[1].remove("MAP_NUM(").remove(")"), i, li[2].toUShort(), li[3].toUShort());
parsed->append(hloc);
i++;
}
}
return parsed;
}
QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers) {
QList<Token> tokens;
QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen");
QRegularExpression re("^(?<hex>0x[0-9a-fA-F]+)|(?<decimal>[0-9]+)|(?<identifier>[a-zA-Z_0-9]+)|(?<operator>[+\\-*\\/<>|^%]+)|(?<leftparen>\\()|(?<rightparen>\\))");
expression = expression.trimmed();
while (!expression.isEmpty()) {
QRegularExpressionMatch match = re.match(expression);
if (!match.hasMatch()) {
qDebug() << "Failed to tokenize expression: " << expression;
break;
}
for (QString tokenType : tokenTypes) {
QString token = match.captured(tokenType);
if (!token.isEmpty()) {
if (tokenType == "identifier") {
if (knownIdentifiers->contains(token)) {
QString actualToken = QString("%1").arg(knownIdentifiers->value(token));
expression = expression.replace(0, token.length(), actualToken);
token = actualToken;
tokenType = "decimal";
} else {
qDebug() << "Unknown identifier found in expression: " << token;
}
}
tokens.append(Token(token, tokenType));
expression = expression.remove(0, token.length()).trimmed();
break;
}
}
}
return tokens;
}
QMap<QString, int> Token::precedenceMap = QMap<QString, int>(
{
{"*", 3},
{"/", 3},
{"+", 4},
{"-", 4},
{"<<", 5},
{">>", 5},
{"&", 8},
{"^", 9},
{"|", 10}
});
// Shunting-yard algorithm for generating postfix notation.
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
QList<Token> ParseUtil::generatePostfix(QList<Token> tokens) {
QList<Token> output;
QStack<Token> operatorStack;
for (Token token : tokens) {
if (token.type == TokenType::Number) {
output.append(token);
} else if (token.value == "(") {
operatorStack.push(token);
} else if (token.value == ")") {
while (!operatorStack.empty() && operatorStack.top().value != "(") {
output.append(operatorStack.pop());
}
if (!operatorStack.empty()) {
// pop the left parenthesis token
operatorStack.pop();
} else {
qDebug() << "Mismatched parentheses detected in expression!";
}
} else {
// token is an operator
while (!operatorStack.isEmpty()
&& operatorStack.top().operatorPrecedence <= token.operatorPrecedence
&& operatorStack.top().value != "(") {
output.append(operatorStack.pop());
}
operatorStack.push(token);
}
}
while (!operatorStack.isEmpty()) {
if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
qDebug() << "Mismatched parentheses detected in expression!";
} else {
output.append(operatorStack.pop());
}
}
return output;
}
// Evaluate postfix expression.
// https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm
int ParseUtil::evaluatePostfix(QList<Token> postfix) {
QStack<Token> stack;
for (Token token : postfix) {
if (token.type == TokenType::Operator) {
int op2 = stack.pop().value.toInt(nullptr, 0);
int op1 = stack.pop().value.toInt(nullptr, 0);
int result = 0;
if (token.value == "*") {
result = op1 * op2;
} else if (token.value == "/") {
result = op1 / op2;
} else if (token.value == "+") {
result = op1 + op2;
} else if (token.value == "-") {
result = op1 - op2;
} else if (token.value == "<<") {
result = op1 << op2;
} else if (token.value == ">>") {
result = op1 >> op2;
} else if (token.value == "&") {
result = op1 & op2;
} else if (token.value == "^") {
result = op1 ^ op2;
} else if (token.value == "|") {
result = op1 | op2;
} else {
qDebug() << "Unsupported postfix operator: " << token.value;
}
stack.push(Token(QString("%1").arg(result), "decimal"));
} else {
stack.push(token);
}
}
return stack.pop().value.toInt(nullptr, 0);
}
#include "parseutil.h"
#include <QDebug>
#include <QRegularExpression>
#include <QStack>
ParseUtil::ParseUtil()
{
}
void ParseUtil::strip_comment(QString *line) {
bool in_string = false;
for (int i = 0; i < line->length(); i++) {
if (line->at(i) == '"') {
in_string = !in_string;
} else if (line->at(i) == '@') {
if (!in_string) {
line->truncate(i);
break;
}
}
}
}
QList<QStringList>* ParseUtil::parseAsm(QString text) {
QList<QStringList> *parsed = new QList<QStringList>;
QStringList lines = text.split('\n');
for (QString line : lines) {
QString label;
//QString macro;
//QStringList *params;
strip_comment(&line);
if (line.trimmed().isEmpty()) {
} else if (line.contains(':')) {
label = line.left(line.indexOf(':'));
QStringList *list = new QStringList;
list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
list->append(label);
parsed->append(*list);
// There should not be anything else on the line.
// gas will raise a syntax error if there is.
} else {
line = line.trimmed();
//parsed->append(line.split(QRegExp("\\s*,\\s*")));
QString macro;
QStringList params;
int index = line.indexOf(QRegExp("\\s+"));
macro = line.left(index);
params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
params.prepend(macro);
parsed->append(params);
}
//if (macro != NULL) {
// if (macros->contains(macro)) {
// void* function = macros->value(macro);
// if (function != NULL) {
// std::function function(params);
// }
// }
//}
}
return parsed;
}
int ParseUtil::evaluateDefine(QString define, QMap<QString, int>* knownDefines) {
QList<Token> tokens = tokenizeExpression(define, knownDefines);
QList<Token> postfixExpression = generatePostfix(tokens);
return evaluatePostfix(postfixExpression);
}
// arg here is the text in the file src/data/heal_locations.h
// returns a list of HealLocations (mapname, x, y)
QList<HealLocation>* ParseUtil::parseHealLocs(QString text) {
QList<HealLocation> *parsed = new QList<HealLocation>;
QStringList lines = text.split('\n');
int i = 1;
for (auto line : lines){
if (line.contains("MAP_GROUP")){
QList<QString> li = line.replace(" ","").chopped(2).remove('{').split(',');
HealLocation hloc = HealLocation(li[1].remove("MAP_NUM(").remove(")"), i, li[2].toUShort(), li[3].toUShort());
parsed->append(hloc);
i++;
}
}
return parsed;
}
QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers) {
QList<Token> tokens;
QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen");
QRegularExpression re("^(?<hex>0x[0-9a-fA-F]+)|(?<decimal>[0-9]+)|(?<identifier>[a-zA-Z_0-9]+)|(?<operator>[+\\-*\\/<>|^%]+)|(?<leftparen>\\()|(?<rightparen>\\))");
expression = expression.trimmed();
while (!expression.isEmpty()) {
QRegularExpressionMatch match = re.match(expression);
if (!match.hasMatch()) {
qDebug() << "Failed to tokenize expression: " << expression;
break;
}
for (QString tokenType : tokenTypes) {
QString token = match.captured(tokenType);
if (!token.isEmpty()) {
if (tokenType == "identifier") {
if (knownIdentifiers->contains(token)) {
QString actualToken = QString("%1").arg(knownIdentifiers->value(token));
expression = expression.replace(0, token.length(), actualToken);
token = actualToken;
tokenType = "decimal";
} else {
qDebug() << "Unknown identifier found in expression: " << token;
}
}
tokens.append(Token(token, tokenType));
expression = expression.remove(0, token.length()).trimmed();
break;
}
}
}
return tokens;
}
QMap<QString, int> Token::precedenceMap = QMap<QString, int>(
{
{"*", 3},
{"/", 3},
{"+", 4},
{"-", 4},
{"<<", 5},
{">>", 5},
{"&", 8},
{"^", 9},
{"|", 10}
});
// Shunting-yard algorithm for generating postfix notation.
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
QList<Token> ParseUtil::generatePostfix(QList<Token> tokens) {
QList<Token> output;
QStack<Token> operatorStack;
for (Token token : tokens) {
if (token.type == TokenType::Number) {
output.append(token);
} else if (token.value == "(") {
operatorStack.push(token);
} else if (token.value == ")") {
while (!operatorStack.empty() && operatorStack.top().value != "(") {
output.append(operatorStack.pop());
}
if (!operatorStack.empty()) {
// pop the left parenthesis token
operatorStack.pop();
} else {
qDebug() << "Mismatched parentheses detected in expression!";
}
} else {
// token is an operator
while (!operatorStack.isEmpty()
&& operatorStack.top().operatorPrecedence <= token.operatorPrecedence
&& operatorStack.top().value != "(") {
output.append(operatorStack.pop());
}
operatorStack.push(token);
}
}
while (!operatorStack.isEmpty()) {
if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
qDebug() << "Mismatched parentheses detected in expression!";
} else {
output.append(operatorStack.pop());
}
}
return output;
}
// Evaluate postfix expression.
// https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm
int ParseUtil::evaluatePostfix(QList<Token> postfix) {
QStack<Token> stack;
for (Token token : postfix) {
if (token.type == TokenType::Operator) {
int op2 = stack.pop().value.toInt(nullptr, 0);
int op1 = stack.pop().value.toInt(nullptr, 0);
int result = 0;
if (token.value == "*") {
result = op1 * op2;
} else if (token.value == "/") {
result = op1 / op2;
} else if (token.value == "+") {
result = op1 + op2;
} else if (token.value == "-") {
result = op1 - op2;
} else if (token.value == "<<") {
result = op1 << op2;
} else if (token.value == ">>") {
result = op1 >> op2;
} else if (token.value == "&") {
result = op1 & op2;
} else if (token.value == "^") {
result = op1 ^ op2;
} else if (token.value == "|") {
result = op1 | op2;
} else {
qDebug() << "Unsupported postfix operator: " << token.value;
}
stack.push(Token(QString("%1").arg(result), "decimal"));
} else {
stack.push(token);
}
}
return stack.pop().value.toInt(nullptr, 0);
}

12
tile.cpp → src/core/tile.cpp Executable file → Normal file
View file

@ -1,6 +1,6 @@
#include "tile.h"
Tile::Tile()
{
}
#include "tile.h"
Tile::Tile()
{
}

89
src/core/tileset.cpp Normal file
View file

@ -0,0 +1,89 @@
#include "tileset.h"
#include "metatile.h"
#include "project.h"
#include <QPainter>
#include <QImage>
#include <QDebug>
Tileset::Tileset()
{
}
Tileset* Tileset::copy() {
Tileset *copy = new Tileset;
copy->name = this->name;
copy->is_compressed = this->is_compressed;
copy->is_secondary = this->is_secondary;
copy->padding = this->padding;
copy->tiles_label = this->tiles_label;
copy->palettes_label = this->palettes_label;
copy->metatiles_label = this->metatiles_label;
copy->metatiles_path = this->metatiles_path;
copy->callback_label = this->callback_label;
copy->metatile_attrs_label = this->metatile_attrs_label;
copy->metatile_attrs_path = this->metatile_attrs_path;
copy->tilesImage = this->tilesImage.copy();
copy->tilesImagePath = this->tilesImagePath;
for (int i = 0; i < this->palettePaths.length(); i++) {
copy->palettePaths.append(this->palettePaths.at(i));
}
copy->tiles = new QList<QImage>;
for (QImage tile : *this->tiles) {
copy->tiles->append(tile.copy());
}
copy->metatiles = new QList<Metatile*>;
for (Metatile *metatile : *this->metatiles) {
copy->metatiles->append(metatile->copy());
}
copy->palettes = new QList<QList<QRgb>>;
for (QList<QRgb> palette : *this->palettes) {
QList<QRgb> copyPalette;
for (QRgb color : palette) {
copyPalette.append(color);
}
copy->palettes->append(copyPalette);
}
return copy;
}
Tileset* Tileset::getBlockTileset(int metatile_index, Tileset *primaryTileset, Tileset *secondaryTileset) {
if (metatile_index < Project::getNumMetatilesPrimary()) {
return primaryTileset;
} else {
return secondaryTileset;
}
}
Metatile* Tileset::getMetatile(int index, Tileset *primaryTileset, Tileset *secondaryTileset) {
Tileset *tileset = Tileset::getBlockTileset(index, primaryTileset, secondaryTileset);
int local_index = Metatile::getBlockIndex(index);
if (!tileset || !tileset->metatiles) {
return nullptr;
}
Metatile *metatile = tileset->metatiles->value(local_index, nullptr);
return metatile;
}
QList<QList<QRgb>> Tileset::getBlockPalettes(Tileset *primaryTileset, Tileset *secondaryTileset) {
QList<QList<QRgb>> palettes;
for (int i = 0; i < Project::getNumPalettesPrimary(); i++) {
palettes.append(primaryTileset->palettes->at(i));
}
for (int i = Project::getNumPalettesPrimary(); i < Project::getNumPalettesTotal(); i++) {
palettes.append(secondaryTileset->palettes->at(i));
}
return palettes;
}
QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset *secondaryTileset) {
QList<QRgb> paletteTable;
Tileset *tileset = paletteId < Project::getNumPalettesPrimary()
? primaryTileset
: secondaryTileset;
for (int i = 0; i < tileset->palettes->at(paletteId).length(); i++) {
paletteTable.append(tileset->palettes->at(paletteId).at(i));
}
return paletteTable;
}

2939
editor.cpp → src/editor.cpp Executable file → Normal file

File diff suppressed because it is too large Load diff

24
main.cpp → src/main.cpp Executable file → Normal file
View file

@ -1,12 +1,12 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
w.show();
return a.exec();
}
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
w.show();
return a.exec();
}

2449
mainwindow.cpp → src/mainwindow.cpp Executable file → Normal file

File diff suppressed because it is too large Load diff

3636
project.cpp → src/project.cpp Executable file → Normal file

File diff suppressed because it is too large Load diff

6
src/settings.cpp Normal file
View file

@ -0,0 +1,6 @@
#include "settings.h"
Settings::Settings()
{
}

View file

@ -0,0 +1,42 @@
#include "bordermetatilespixmapitem.h"
#include "imageproviders.h"
#include <QPainter>
void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
for (int i = 0; i < selectionDimensions.x() && (i + x) < 2; i++) {
for (int j = 0; j < selectionDimensions.y() && (j + y) < 2; j++) {
int blockIndex = (j + y) * 2 + (i + x);
uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
(*map->layout->border->blocks)[blockIndex].tile = tile;
}
}
draw();
emit borderMetatilesChanged();
}
void BorderMetatilesPixmapItem::draw() {
QImage image(32, 32, QImage::Format_RGBA8888);
QPainter painter(&image);
QList<Block> *blocks = map->layout->border->blocks;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
int x = i * 16;
int y = j * 16;
int index = j * 2 + i;
QImage metatile_image = getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary);
QPoint metatile_origin = QPoint(x, y);
painter.drawImage(metatile_origin, metatile_image);
}
}
painter.end();
this->setPixmap(QPixmap::fromImage(image));
}

View file

@ -0,0 +1,86 @@
#include "collisionpixmapitem.h"
void CollisionPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
int x = static_cast<int>(event->pos().x()) / 16;
int y = static_cast<int>(event->pos().y()) / 16;
emit this->hoveredMapMovementPermissionChanged(x, y);
if (this->settings->betterCursors){
setCursor(this->settings->mapCursor);
}
}
void CollisionPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
emit this->hoveredMapMovementPermissionCleared();
if (this->settings->betterCursors){
unsetCursor();
}
}
void CollisionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
emit mouseEvent(event, this);
}
void CollisionPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
emit mouseEvent(event, this);
}
void CollisionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
emit mouseEvent(event, this);
}
void CollisionPixmapItem::draw(bool ignoreCache) {
if (map) {
setPixmap(map->renderCollision(ignoreCache));
}
}
void CollisionPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
if (map) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(x, y);
if (block) {
block->collision = this->movementPermissionsSelector->getSelectedCollision();
block->elevation = this->movementPermissionsSelector->getSelectedElevation();
map->_setBlock(x, y, *block);
}
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
map->commit();
}
draw();
}
}
void CollisionPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
if (map) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
uint16_t collision = this->movementPermissionsSelector->getSelectedCollision();
uint16_t elevation = this->movementPermissionsSelector->getSelectedElevation();
map->floodFillCollisionElevation(x, y, collision, elevation);
draw();
}
}
void CollisionPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(x, y);
if (block) {
this->movementPermissionsSelector->select(block->collision, block->elevation);
}
}
void CollisionPixmapItem::updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
// Snap point to within map bounds.
if (x < 0) x = 0;
if (x >= map->getWidth()) x = map->getWidth() - 1;
if (y < 0) y = 0;
if (y >= map->getHeight()) y = map->getHeight() - 1;
Block *block = map->getBlock(x, y);
this->movementPermissionsSelector->select(block->collision, block->elevation);
}

View file

@ -0,0 +1,72 @@
#include "connectionpixmapitem.h"
void ConnectionPixmapItem::render(qreal opacity) {
QPixmap newPixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
if (opacity < 1) {
QPainter painter(&newPixmap);
int alpha = static_cast<int>(255 * (1 - opacity));
painter.fillRect(0, 0, newPixmap.width(), newPixmap.height(), QColor(0, 0, 0, alpha));
painter.end();
}
this->setPixmap(newPixmap);
}
int ConnectionPixmapItem::getMinOffset() {
if (this->connection->direction == "up" || this->connection->direction == "down")
return 1 - (this->pixmap().width() / 16);
else
return 1 - (this->pixmap().height() / 16);
}
int ConnectionPixmapItem::getMaxOffset() {
if (this->connection->direction == "up" || this->connection->direction == "down")
return this->baseMapWidth - 1;
else
return this->baseMapHeight - 1;
}
QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange) {
QPointF newPos = value.toPointF();
qreal x, y;
int newOffset = this->initialOffset;
if (this->connection->direction == "up" || this->connection->direction == "down") {
x = round(newPos.x() / 16) * 16;
newOffset += (x - initialX) / 16;
newOffset = qMin(newOffset, this->getMaxOffset());
newOffset = qMax(newOffset, this->getMinOffset());
x = newOffset * 16;
}
else {
x = this->initialX;
}
if (this->connection->direction == "right" || this->connection->direction == "left") {
y = round(newPos.y() / 16) * 16;
newOffset += (y - this->initialY) / 16;
newOffset = qMin(newOffset, this->getMaxOffset());
newOffset = qMax(newOffset, this->getMinOffset());
y = newOffset * 16;
}
else {
y = this->initialY;
}
this->connection->offset = QString::number(newOffset);
emit connectionMoved(this->connection);
return QPointF(x, y);
}
else {
return QGraphicsItem::itemChange(change, value);
}
}
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
emit connectionItemSelected(this);
}
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
emit connectionItemDoubleClicked(this);
}

View file

@ -0,0 +1,26 @@
#include "currentselectedmetatilespixmapitem.h"
#include "imageproviders.h"
#include <QPainter>
void CurrentSelectedMetatilesPixmapItem::draw() {
QList<uint16_t> *selectedMetatiles = metatileSelector->getSelectedMetatiles();
QPoint selectionDimensions = metatileSelector->getSelectionDimensions();
int width = selectionDimensions.x() * 16;
int height = selectionDimensions.y() * 16;
QImage image(width, height, QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < selectionDimensions.x(); i++) {
for (int j = 0; j < selectionDimensions.y(); j++) {
int x = i * 16;
int y = j * 16;
int index = j * selectionDimensions.x() + i;
QImage metatile_image = getMetatileImage(selectedMetatiles->at(index), map->layout->tileset_primary, map->layout->tileset_secondary);
QPoint metatile_origin = QPoint(x, y);
painter.drawImage(metatile_origin, metatile_image);
}
}
painter.end();
setPixmap(QPixmap::fromImage(image));
}

View file

@ -0,0 +1,14 @@
#include "eventpropertiesframe.h"
#include "ui_eventpropertiesframe.h"
EventPropertiesFrame::EventPropertiesFrame(QWidget *parent) :
QFrame(parent),
ui(new Ui::EventPropertiesFrame)
{
ui->setupUi(this);
}
EventPropertiesFrame::~EventPropertiesFrame()
{
delete ui;
}

34
graphicsview.cpp → src/ui/graphicsview.cpp Executable file → Normal file
View file

@ -1,17 +1,17 @@
#include "graphicsview.h"
#include "editor.h"
void GraphicsView::mousePressEvent(QMouseEvent *event) {
QGraphicsView::mousePressEvent(event);
if (editor) {
editor->objectsView_onMousePress(event);
}
}
void GraphicsView::mouseMoveEvent(QMouseEvent *event) {
QGraphicsView::mouseMoveEvent(event);
}
void GraphicsView::mouseReleaseEvent(QMouseEvent *event) {
QGraphicsView::mouseReleaseEvent(event);
}
#include "graphicsview.h"
#include "editor.h"
void GraphicsView::mousePressEvent(QMouseEvent *event) {
QGraphicsView::mousePressEvent(event);
if (editor) {
editor->objectsView_onMousePress(event);
}
}
void GraphicsView::mouseMoveEvent(QMouseEvent *event) {
QGraphicsView::mouseMoveEvent(event);
}
void GraphicsView::mouseReleaseEvent(QMouseEvent *event) {
QGraphicsView::mouseReleaseEvent(event);
}

97
src/ui/imageproviders.cpp Normal file
View file

@ -0,0 +1,97 @@
#include "imageproviders.h"
#include <QPainter>
#include <QDebug>
QImage getCollisionMetatileImage(Block block) {
return getCollisionMetatileImage(block.collision, block.elevation);
}
QImage getCollisionMetatileImage(int collision, int elevation) {
int x = collision * 16;
int y = elevation * 16;
QPixmap collisionImage = QPixmap(":/images/collisions.png").copy(x, y, 16, 16);
return collisionImage.toImage();
}
QImage getMetatileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
Metatile* metatile = Tileset::getMetatile(tile, primaryTileset, secondaryTileset);
if (!metatile || !metatile->tiles) {
metatile_image.fill(0xffffffff);
return metatile_image;
}
Tileset* blockTileset = Tileset::getBlockTileset(tile, primaryTileset, secondaryTileset);
if (!blockTileset) {
metatile_image.fill(0xffffffff);
return metatile_image;
}
QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset);
QPainter metatile_painter(&metatile_image);
for (int layer = 0; layer < 2; layer++)
for (int y = 0; y < 2; y++)
for (int x = 0; x < 2; x++) {
Tile tile_ = metatile->tiles->value((y * 2) + x + (layer * 4));
QImage tile_image = getTileImage(tile_.tile, primaryTileset, secondaryTileset);
if (tile_image.isNull()) {
// Some metatiles specify tiles that are outside the valid range.
// These are treated as completely transparent, so they can be skipped without
// being drawn unless they're on the bottom layer, in which case we need
// a placeholder because garbage will be drawn otherwise.
if (layer == 0) {
metatile_painter.fillRect(x * 8, y * 8, 8, 8, palettes.value(0).value(0));
}
continue;
}
// Colorize the metatile tiles with its palette.
if (tile_.palette < palettes.length()) {
QList<QRgb> palette = palettes.value(tile_.palette);
for (int j = 0; j < palette.length(); j++) {
tile_image.setColor(j, palette.value(j));
}
} else {
qDebug() << "Tile is referring to invalid palette number: " << tile_.palette;
}
// The top layer of the metatile has its first color displayed at transparent.
if (layer > 0) {
QColor color(tile_image.color(0));
color.setAlpha(0);
tile_image.setColor(0, color.rgba());
}
QPoint origin = QPoint(x*8, y*8);
metatile_painter.drawImage(origin, tile_image.mirrored(tile_.xflip == 1, tile_.yflip == 1));
}
metatile_painter.end();
return metatile_image;
}
QImage getTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
Tileset *tileset = Tileset::getBlockTileset(tile, primaryTileset, secondaryTileset);
int local_index = Metatile::getBlockIndex(tile);
if (!tileset || !tileset->tiles) {
return QImage();
}
return tileset->tiles->value(local_index, QImage());
}
QImage getColoredTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId) {
QList<QRgb> palette = Tileset::getPalette(paletteId, primaryTileset, secondaryTileset);
QImage tileImage = getTileImage(tile, primaryTileset, secondaryTileset);
if (tileImage.isNull()) {
tileImage = QImage(16, 16, QImage::Format_RGBA8888);
QPainter painter(&tileImage);
painter.fillRect(0, 0, 16, 16, palette.at(0));
} else {
for (int i = 0; i < 16; i++) {
tileImage.setColor(i, palette.at(i));
}
}
return tileImage;
}

480
src/ui/mappixmapitem.cpp Normal file
View file

@ -0,0 +1,480 @@
#include "mappixmapitem.h"
#define SWAP(a, b) do { if (a != b) { a ^= b; b ^= a; a ^= b; } } while (0)
void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
if (map) {
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
map->commit();
} else {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
// Paint onto the map.
bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier;
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) {
paintSmartPath(x, y);
} else {
paintNormal(x, y);
}
}
draw();
}
}
void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
if (map) {
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
map->commit();
} else {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
if (event->type() == QEvent::GraphicsSceneMousePress) {
selection_origin = QPoint(x, y);
selection.clear();
} else if (event->type() == QEvent::GraphicsSceneMouseMove) {
if (x != selection_origin.x() || y != selection_origin.y()) {
int xDelta = x - selection_origin.x();
int yDelta = y - selection_origin.y();
Blockdata *backupBlockdata = map->layout->blockdata->copy();
for (int i = 0; i < map->getWidth(); i++)
for (int j = 0; j < map->getHeight(); j++) {
int destX = i + xDelta;
int destY = j + yDelta;
if (destX < 0)
do { destX += map->getWidth(); } while (destX < 0);
if (destY < 0)
do { destY += map->getHeight(); } while (destY < 0);
destX %= map->getWidth();
destY %= map->getHeight();
int blockIndex = j * map->getWidth() + i;
Block srcBlock = backupBlockdata->blocks->at(blockIndex);
map->_setBlock(destX, destY, srcBlock);
}
delete backupBlockdata;
selection_origin = QPoint(x, y);
selection.clear();
draw();
}
}
}
}
}
void MapPixmapItem::paintNormal(int x, int y) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
// Snap the selected position to the top-left of the block boundary.
// This allows painting via dragging the mouse to tile the painted region.
int xDiff = x - this->paint_tile_initial_x;
int yDiff = y - this->paint_tile_initial_y;
if (xDiff < 0 && xDiff % selectionDimensions.x() != 0) xDiff -= selectionDimensions.x();
if (yDiff < 0 && yDiff % selectionDimensions.y() != 0) yDiff -= selectionDimensions.y();
x = this->paint_tile_initial_x + (xDiff / selectionDimensions.x()) * selectionDimensions.x();
y = this->paint_tile_initial_y + (yDiff / selectionDimensions.y()) * selectionDimensions.y();
for (int i = 0; i < selectionDimensions.x() && i + x < map->getWidth(); i++)
for (int j = 0; j < selectionDimensions.y() && j + y < map->getHeight(); j++) {
int actualX = i + x;
int actualY = j + y;
Block *block = map->getBlock(actualX, actualY);
if (block) {
block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
map->_setBlock(actualX, actualY, *block);
}
}
}
// These are tile offsets from the top-left tile in the 3x3 smart path selection.
// Each entry is for one possibility from the marching squares value for a tile.
// (Marching Squares: https://en.wikipedia.org/wiki/Marching_squares)
QList<int> MapPixmapItem::smartPathTable = QList<int>({
4, // 0000
4, // 0001
4, // 0010
6, // 0011
4, // 0100
4, // 0101
0, // 0110
3, // 0111
4, // 1000
8, // 1001
4, // 1010
7, // 1011
2, // 1100
5, // 1101
1, // 1110
4, // 1111
});
#define IS_SMART_PATH_TILE(block) (selectedMetatiles->contains(block->tile))
void MapPixmapItem::paintSmartPath(int x, int y) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
// Smart path should never be enabled without a 3x3 block selection.
if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return;
// Shift to the middle tile of the smart path selection.
uint16_t openTile = selectedMetatiles->at(4);
// Fill the region with the open tile.
for (int i = 0; i <= 1; i++)
for (int j = 0; j <= 1; j++) {
// Check if in map bounds.
if (!(i + x < map->getWidth() && i + x >= 0 && j + y < map->getHeight() && j + y >= 0))
continue;
int actualX = i + x;
int actualY = j + y;
Block *block = map->getBlock(actualX, actualY);
if (block) {
block->tile = openTile;
map->_setBlock(actualX, actualY, *block);
}
}
// Go back and resolve the edge tiles
for (int i = -1; i <= 2; i++)
for (int j = -1; j <= 2; j++) {
// Check if in map bounds.
if (!(i + x < map->getWidth() && i + x >= 0 && j + y < map->getHeight() && j + y >= 0))
continue;
// Ignore the corners, which can't possible be affected by the smart path.
if ((i == -1 && j == -1) || (i == 2 && j == -1) ||
(i == -1 && j == 2) || (i == 2 && j == 2))
continue;
// Ignore tiles that aren't part of the smart path set.
int actualX = i + x;
int actualY = j + y;
Block *block = map->getBlock(actualX, actualY);
if (!block || !IS_SMART_PATH_TILE(block)) {
continue;
}
int id = 0;
Block *top = map->getBlock(actualX, actualY - 1);
Block *right = map->getBlock(actualX + 1, actualY);
Block *bottom = map->getBlock(actualX, actualY + 1);
Block *left = map->getBlock(actualX - 1, actualY);
// Get marching squares value, to determine which tile to use.
if (top && IS_SMART_PATH_TILE(top))
id += 1;
if (right && IS_SMART_PATH_TILE(right))
id += 2;
if (bottom && IS_SMART_PATH_TILE(bottom))
id += 4;
if (left && IS_SMART_PATH_TILE(left))
id += 8;
block->tile = selectedMetatiles->at(smartPathTable[id]);
map->_setBlock(actualX, actualY, *block);
}
}
void MapPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
// Snap point to within map bounds.
if (x < 0) x = 0;
if (x >= map->getWidth()) x = map->getWidth() - 1;
if (y < 0) y = 0;
if (y >= map->getHeight()) y = map->getHeight() - 1;
// Update/apply copied metatiles.
if (event->type() == QEvent::GraphicsSceneMousePress) {
selection_origin = QPoint(x, y);
selection.clear();
selection.append(QPoint(x, y));
uint16_t metatileId = map->getBlock(x, y)->tile;
this->metatileSelector->select(metatileId);
} else if (event->type() == QEvent::GraphicsSceneMouseMove) {
QPoint pos = QPoint(x, y);
int x1 = selection_origin.x();
int y1 = selection_origin.y();
int x2 = pos.x();
int y2 = pos.y();
if (x1 > x2) SWAP(x1, x2);
if (y1 > y2) SWAP(y1, y2);
selection.clear();
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
selection.append(QPoint(x, y));
}
}
QList<uint16_t> metatiles;
for (QPoint point : selection) {
metatiles.append(map->getBlock(point.x(), point.y())->tile);
}
this->metatileSelector->setExternalSelection(x2 - x1 + 1, y2 - y1 + 1, &metatiles);
}
}
void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
if (map) {
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
map->commit();
} else {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(x, y);
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
int tile = selectedMetatiles->first();
if (block && block->tile != tile) {
bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier;
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3)
this->_floodFillSmartPath(x, y);
else
this->_floodFill(x, y);
}
}
draw();
}
}
void MapPixmapItem::_floodFill(int initialX, int initialY) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPoint> todo;
todo.append(QPoint(initialX, initialY));
while (todo.length()) {
QPoint point = todo.takeAt(0);
int x = point.x();
int y = point.y();
Block *block = map->getBlock(x, y);
if (!block) {
continue;
}
int xDiff = x - initialX;
int yDiff = y - initialY;
int i = xDiff % selectionDimensions.x();
int j = yDiff % selectionDimensions.y();
if (i < 0) i = selectionDimensions.x() + i;
if (j < 0) j = selectionDimensions.y() + j;
uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
uint16_t old_tile = block->tile;
if (old_tile == tile) {
continue;
}
block->tile = tile;
map->_setBlock(x, y, *block);
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y));
}
if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x - 1, y));
}
if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
todo.append(QPoint(x, y + 1));
}
if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
todo.append(QPoint(x, y - 1));
}
}
}
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
// Smart path should never be enabled without a 3x3 block selection.
if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return;
// Shift to the middle tile of the smart path selection.
uint16_t openTile = selectedMetatiles->at(4);
// Flood fill the region with the open tile.
QList<QPoint> todo;
todo.append(QPoint(initialX, initialY));
while (todo.length()) {
QPoint point = todo.takeAt(0);
int x = point.x();
int y = point.y();
Block *block = map->getBlock(x, y);
if (!block) {
continue;
}
uint16_t old_tile = block->tile;
if (old_tile == openTile) {
continue;
}
block->tile = openTile;
map->_setBlock(x, y, *block);
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y));
}
if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x - 1, y));
}
if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
todo.append(QPoint(x, y + 1));
}
if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
todo.append(QPoint(x, y - 1));
}
}
// Go back and resolve the flood-filled edge tiles.
// Mark tiles as visited while we go.
int numMetatiles = map->getWidth() * map->getHeight();
bool *visited = new bool[numMetatiles];
for (int i = 0; i < numMetatiles; i++)
visited[i] = false;
todo.append(QPoint(initialX, initialY));
while (todo.length()) {
QPoint point = todo.takeAt(0);
int x = point.x();
int y = point.y();
visited[x + y * map->getWidth()] = true;
Block *block = map->getBlock(x, y);
if (!block) {
continue;
}
int id = 0;
Block *top = map->getBlock(x, y - 1);
Block *right = map->getBlock(x + 1, y);
Block *bottom = map->getBlock(x, y + 1);
Block *left = map->getBlock(x - 1, y);
// Get marching squares value, to determine which tile to use.
if (top && IS_SMART_PATH_TILE(top))
id += 1;
if (right && IS_SMART_PATH_TILE(right))
id += 2;
if (bottom && IS_SMART_PATH_TILE(bottom))
id += 4;
if (left && IS_SMART_PATH_TILE(left))
id += 8;
block->tile = selectedMetatiles->at(smartPathTable[id]);
map->_setBlock(x, y, *block);
// Visit neighbors if they are smart-path tiles, and don't revisit any.
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && IS_SMART_PATH_TILE(block)) {
todo.append(QPoint(x + 1, y));
visited[x + 1 + y * map->getWidth()] = true;
}
if (!visited[x - 1 + y * map->getWidth()] && (block = map->getBlock(x - 1, y)) && IS_SMART_PATH_TILE(block)) {
todo.append(QPoint(x - 1, y));
visited[x - 1 + y * map->getWidth()] = true;
}
if (!visited[x + (y + 1) * map->getWidth()] && (block = map->getBlock(x, y + 1)) && IS_SMART_PATH_TILE(block)) {
todo.append(QPoint(x, y + 1));
visited[x + (y + 1) * map->getWidth()] = true;
}
if (!visited[x + (y - 1) * map->getWidth()] && (block = map->getBlock(x, y - 1)) && IS_SMART_PATH_TILE(block)) {
todo.append(QPoint(x, y - 1));
visited[x + (y - 1) * map->getWidth()] = true;
}
}
delete[] visited;
}
void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(x, y);
if (block) {
this->metatileSelector->select(block->tile);
}
}
void MapPixmapItem::select(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
if (event->type() == QEvent::GraphicsSceneMousePress) {
selection_origin = QPoint(x, y);
selection.clear();
} else if (event->type() == QEvent::GraphicsSceneMouseMove) {
if (event->buttons() & Qt::LeftButton) {
selection.clear();
selection.append(QPoint(x, y));
}
} else if (event->type() == QEvent::GraphicsSceneMouseRelease) {
if (!selection.isEmpty()) {
QPoint pos = selection.last();
int x1 = selection_origin.x();
int y1 = selection_origin.y();
int x2 = pos.x();
int y2 = pos.y();
if (x1 > x2) SWAP(x1, x2);
if (y1 > y2) SWAP(y1, y2);
selection.clear();
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
selection.append(QPoint(x, y));
}
}
qDebug() << QString("selected (%1, %2) -> (%3, %4)").arg(x1).arg(y1).arg(x2).arg(y2);
}
}
}
void MapPixmapItem::draw(bool ignoreCache) {
if (map) {
setPixmap(map->render(ignoreCache));
}
}
void MapPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
int x = static_cast<int>(event->pos().x()) / 16;
int y = static_cast<int>(event->pos().y()) / 16;
emit this->hoveredMapMetatileChanged(x, y);
if (this->settings->betterCursors){
setCursor(this->settings->mapCursor);
}
}
void MapPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
emit this->hoveredMapMetatileCleared();
if (this->settings->betterCursors){
unsetCursor();
}
}
void MapPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
this->paint_tile_initial_x = x;
this->paint_tile_initial_y = y;
emit mouseEvent(event, this);
}
void MapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
int x = static_cast<int>(event->pos().x()) / 16;
int y = static_cast<int>(event->pos().y()) / 16;
emit this->hoveredMapMetatileChanged(x, y);
emit mouseEvent(event, this);
}
void MapPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
emit mouseEvent(event, this);
}

View file

@ -0,0 +1,23 @@
#include "mapsceneeventfilter.h"
#include <QEvent>
#include <QGraphicsSceneWheelEvent>
MapSceneEventFilter::MapSceneEventFilter(QObject *parent) : QObject(parent)
{
}
bool MapSceneEventFilter::eventFilter(QObject*, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
QGraphicsSceneWheelEvent *wheelEvent = static_cast<QGraphicsSceneWheelEvent *>(event);
if (wheelEvent->modifiers() & Qt::ControlModifier)
{
emit wheelZoom(wheelEvent->delta() > 0 ? 1 : -1);
event->accept();
return true;
}
}
return false;
}

View file

@ -0,0 +1,45 @@
#include "metatilelayersitem.h"
#include "imageproviders.h"
#include <QPainter>
void MetatileLayersItem::draw() {
const QList<QPoint> tileCoords = QList<QPoint>{
QPoint(0, 0),
QPoint(16, 0),
QPoint(0, 16),
QPoint(16, 16),
QPoint(32, 0),
QPoint(48, 0),
QPoint(32, 16),
QPoint(48, 16),
};
QPixmap pixmap(64, 32);
QPainter painter(&pixmap);
for (int i = 0; i < 8; i++) {
Tile tile = this->metatile->tiles->at(i);
QImage tileImage = getColoredTileImage(tile.tile, this->primaryTileset, this->secondaryTileset, tile.palette)
.mirrored(tile.xflip, tile.yflip)
.scaled(16, 16);
painter.drawImage(tileCoords.at(i), tileImage);
}
this->setPixmap(pixmap);
}
void MetatileLayersItem::setMetatile(Metatile *metatile) {
this->metatile = metatile;
}
void MetatileLayersItem::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->draw();
}
void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
emit this->tileChanged(x, y);
}

147
src/ui/metatileselector.cpp Normal file
View file

@ -0,0 +1,147 @@
#include "imageproviders.h"
#include "metatileselector.h"
#include "project.h"
#include <QPainter>
QPoint MetatileSelector::getSelectionDimensions() {
if (this->externalSelection) {
return QPoint(this->externalSelectionWidth, this->externalSelectionHeight);
} else {
return SelectablePixmapItem::getSelectionDimensions();
}
}
void MetatileSelector::draw() {
if (!this->primaryTileset || !this->primaryTileset->metatiles
|| !this->secondaryTileset || !this->secondaryTileset->metatiles) {
this->setPixmap(QPixmap());
}
int primaryLength = this->primaryTileset->metatiles->length();
int length_ = primaryLength + this->secondaryTileset->metatiles->length();
int height_ = length_ / this->numMetatilesWide;
QImage image(this->numMetatilesWide * 16, height_ * 16, QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < length_; i++) {
int tile = i;
if (i >= primaryLength) {
tile += Project::getNumMetatilesPrimary() - primaryLength;
}
QImage metatile_image = getMetatileImage(tile, this->primaryTileset, this->secondaryTileset);
int map_y = i / this->numMetatilesWide;
int map_x = i % this->numMetatilesWide;
QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
painter.drawImage(metatile_origin, metatile_image);
}
painter.end();
this->setPixmap(QPixmap::fromImage(image));
if (!this->externalSelection) {
this->drawSelection();
}
}
void MetatileSelector::select(uint16_t metatileId) {
this->externalSelection = false;
QPoint coords = this->getMetatileIdCoords(metatileId);
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
this->updateSelectedMetatiles();
emit selectedMetatilesChanged();
}
void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->draw();
}
QList<uint16_t>* MetatileSelector::getSelectedMetatiles() {
if (this->externalSelection) {
return this->externalSelectedMetatiles;
} else {
return this->selectedMetatiles;
}
}
void MetatileSelector::setExternalSelection(int width, int height, QList<uint16_t> *metatiles) {
this->externalSelection = true;
this->externalSelectionWidth = width;
this->externalSelectionHeight = height;
this->externalSelectedMetatiles->clear();
for (int i = 0; i < metatiles->length(); i++) {
this->externalSelectedMetatiles->append(metatiles->at(i));
}
this->draw();
emit selectedMetatilesChanged();
}
void MetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedMetatiles();
emit selectedMetatilesChanged();
}
void MetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseMoveEvent(event);
this->updateSelectedMetatiles();
QPoint pos = this->getCellPos(event->pos());
uint16_t metatileId = this->getMetatileId(pos.x(), pos.y());
emit this->hoveredMetatileSelectionChanged(metatileId);
emit selectedMetatilesChanged();
}
void MetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseReleaseEvent(event);
this->updateSelectedMetatiles();
emit selectedMetatilesChanged();
}
void MetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
QPoint pos = this->getCellPos(event->pos());
uint16_t metatileId = this->getMetatileId(pos.x(), pos.y());
emit this->hoveredMetatileSelectionChanged(metatileId);
}
void MetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
emit this->hoveredMetatileSelectionCleared();
}
void MetatileSelector::updateSelectedMetatiles() {
this->externalSelection = false;
this->selectedMetatiles->clear();
QPoint origin = this->getSelectionStart();
QPoint dimensions = this->getSelectionDimensions();
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
uint16_t metatileId = this->getMetatileId(origin.x() + i, origin.y() + j);
this->selectedMetatiles->append(metatileId);
}
}
}
uint16_t MetatileSelector::getMetatileId(int x, int y) {
int index = y * this->numMetatilesWide + x;
if (index < this->primaryTileset->metatiles->length()) {
return static_cast<uint16_t>(index);
} else {
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - this->primaryTileset->metatiles->length());
}
}
QPoint MetatileSelector::getMetatileIdCoords(uint16_t metatileId) {
if (metatileId >= Project::getNumMetatilesTotal()
|| (metatileId < Project::getNumMetatilesPrimary() && metatileId >= this->primaryTileset->metatiles->length())
|| (metatileId < Project::getNumMetatilesTotal() && metatileId >= Project::getNumMetatilesPrimary() + this->secondaryTileset->metatiles->length()))
{
// Invalid metatile id.
return QPoint(0, 0);
}
int index = metatileId < Project::getNumMetatilesPrimary()
? metatileId
: metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->metatiles->length();
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
}

View file

@ -0,0 +1,31 @@
#include "movementpermissionsselector.h"
#include <QPainter>
void MovementPermissionsSelector::draw() {
QPixmap pixmap(":/images/collisions.png");
this->setPixmap(pixmap.scaled(64, 512));
this->drawSelection();
}
uint16_t MovementPermissionsSelector::getSelectedCollision() {
return static_cast<uint16_t>(this->selectionInitialX);
}
uint16_t MovementPermissionsSelector::getSelectedElevation() {
return static_cast<uint16_t>(this->selectionInitialY);
}
void MovementPermissionsSelector::select(uint16_t collision, uint16_t elevation) {
SelectablePixmapItem::select(collision, elevation, 0, 0);
}
void MovementPermissionsSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
QPoint pos = this->getCellPos(event->pos());
uint16_t collision = static_cast<uint16_t>(pos.x());
uint16_t elevation = static_cast<uint16_t>(pos.y());
emit this->hoveredMovementPermissionChanged(collision, elevation);
}
void MovementPermissionsSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
emit this->hoveredMovementPermissionCleared();
}

View file

@ -10,9 +10,10 @@ NewEventToolButton::NewEventToolButton(QWidget *parent) :
setPopupMode(QToolButton::MenuButtonPopup);
QObject::connect(this, SIGNAL(triggered(QAction*)),
this, SLOT(setDefaultAction(QAction*)));
this->init();
}
void NewEventToolButton::initButton()
void NewEventToolButton::init()
{
// Add a context menu to select different types of map events.
this->newObjectAction = new QAction("New Object", this);

176
src/ui/paletteeditor.cpp Normal file
View file

@ -0,0 +1,176 @@
#include "paletteeditor.h"
#include "ui_paletteeditor.h"
PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset *secondaryTileset, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::PaletteEditor)
{
this->project = project;
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->ui->setupUi(this);
this->ui->spinBox_PaletteId->setMinimum(0);
this->ui->spinBox_PaletteId->setMaximum(Project::getNumPalettesTotal() - 1);
this->sliders.clear();
for (int i = 0; i < 16; i++) {
this->sliders.append(QList<QSlider*>());
}
this->sliders[0].append(this->ui->horizontalSlider);
this->sliders[0].append(this->ui->horizontalSlider_2);
this->sliders[0].append(this->ui->horizontalSlider_3);
this->sliders[1].append(this->ui->horizontalSlider_4);
this->sliders[1].append(this->ui->horizontalSlider_5);
this->sliders[1].append(this->ui->horizontalSlider_6);
this->sliders[2].append(this->ui->horizontalSlider_7);
this->sliders[2].append(this->ui->horizontalSlider_8);
this->sliders[2].append(this->ui->horizontalSlider_9);
this->sliders[3].append(this->ui->horizontalSlider_10);
this->sliders[3].append(this->ui->horizontalSlider_11);
this->sliders[3].append(this->ui->horizontalSlider_12);
this->sliders[4].append(this->ui->horizontalSlider_13);
this->sliders[4].append(this->ui->horizontalSlider_14);
this->sliders[4].append(this->ui->horizontalSlider_15);
this->sliders[5].append(this->ui->horizontalSlider_16);
this->sliders[5].append(this->ui->horizontalSlider_17);
this->sliders[5].append(this->ui->horizontalSlider_18);
this->sliders[6].append(this->ui->horizontalSlider_19);
this->sliders[6].append(this->ui->horizontalSlider_20);
this->sliders[6].append(this->ui->horizontalSlider_21);
this->sliders[7].append(this->ui->horizontalSlider_22);
this->sliders[7].append(this->ui->horizontalSlider_23);
this->sliders[7].append(this->ui->horizontalSlider_24);
this->sliders[8].append(this->ui->horizontalSlider_25);
this->sliders[8].append(this->ui->horizontalSlider_26);
this->sliders[8].append(this->ui->horizontalSlider_27);
this->sliders[9].append(this->ui->horizontalSlider_28);
this->sliders[9].append(this->ui->horizontalSlider_29);
this->sliders[9].append(this->ui->horizontalSlider_30);
this->sliders[10].append(this->ui->horizontalSlider_31);
this->sliders[10].append(this->ui->horizontalSlider_32);
this->sliders[10].append(this->ui->horizontalSlider_33);
this->sliders[11].append(this->ui->horizontalSlider_34);
this->sliders[11].append(this->ui->horizontalSlider_35);
this->sliders[11].append(this->ui->horizontalSlider_36);
this->sliders[12].append(this->ui->horizontalSlider_37);
this->sliders[12].append(this->ui->horizontalSlider_38);
this->sliders[12].append(this->ui->horizontalSlider_39);
this->sliders[13].append(this->ui->horizontalSlider_40);
this->sliders[13].append(this->ui->horizontalSlider_41);
this->sliders[13].append(this->ui->horizontalSlider_42);
this->sliders[14].append(this->ui->horizontalSlider_43);
this->sliders[14].append(this->ui->horizontalSlider_44);
this->sliders[14].append(this->ui->horizontalSlider_45);
this->sliders[15].append(this->ui->horizontalSlider_46);
this->sliders[15].append(this->ui->horizontalSlider_47);
this->sliders[15].append(this->ui->horizontalSlider_48);
this->frames.clear();
this->frames.append(this->ui->frame);
this->frames.append(this->ui->frame_2);
this->frames.append(this->ui->frame_3);
this->frames.append(this->ui->frame_4);
this->frames.append(this->ui->frame_5);
this->frames.append(this->ui->frame_6);
this->frames.append(this->ui->frame_7);
this->frames.append(this->ui->frame_8);
this->frames.append(this->ui->frame_9);
this->frames.append(this->ui->frame_10);
this->frames.append(this->ui->frame_11);
this->frames.append(this->ui->frame_12);
this->frames.append(this->ui->frame_13);
this->frames.append(this->ui->frame_14);
this->frames.append(this->ui->frame_15);
this->frames.append(this->ui->frame_16);
this->initColorSliders();
this->refreshColorSliders();
this->refreshColors();
}
PaletteEditor::~PaletteEditor()
{
delete ui;
}
void PaletteEditor::disableSliderSignals() {
for (int i = 0; i < this->sliders.length(); i++) {
this->sliders.at(i).at(0)->blockSignals(true);
this->sliders.at(i).at(1)->blockSignals(true);
this->sliders.at(i).at(2)->blockSignals(true);
}
}
void PaletteEditor::enableSliderSignals() {
for (int i = 0; i < this->sliders.length(); i++) {
this->sliders.at(i).at(0)->blockSignals(false);
this->sliders.at(i).at(1)->blockSignals(false);
this->sliders.at(i).at(2)->blockSignals(false);
}
}
void PaletteEditor::initColorSliders() {
for (int i = 0; i < 16; i++) {
connect(this->sliders[i][0], &QSlider::valueChanged, [=](int) { this->setColor(i); });
connect(this->sliders[i][1], &QSlider::valueChanged, [=](int) { this->setColor(i); });
connect(this->sliders[i][2], &QSlider::valueChanged, [=](int) { this->setColor(i); });
}
}
void PaletteEditor::refreshColorSliders() {
disableSliderSignals();
int paletteNum = this->ui->spinBox_PaletteId->value();
for (int i = 0; i < 16; i++) {
QRgb color;
if (paletteNum < Project::getNumPalettesPrimary()) {
color = this->primaryTileset->palettes->at(paletteNum).at(i);
} else {
color = this->secondaryTileset->palettes->at(paletteNum).at(i);
}
this->sliders[i][0]->setValue(qRed(color) / 8);
this->sliders[i][1]->setValue(qGreen(color) / 8);
this->sliders[i][2]->setValue(qBlue(color) / 8);
}
enableSliderSignals();
}
void PaletteEditor::refreshColors() {
for (int i = 0; i < 16; i++) {
this->refreshColor(i);
}
}
void PaletteEditor::refreshColor(int colorIndex) {
QString stylesheet = QString("background-color: rgb(%1, %2, %3);")
.arg(this->sliders[colorIndex][0]->value() * 8)
.arg(this->sliders[colorIndex][1]->value() * 8)
.arg(this->sliders[colorIndex][2]->value() * 8);
this->frames[colorIndex]->setStyleSheet(stylesheet);
}
void PaletteEditor::setPaletteId(int paletteId) {
this->ui->spinBox_PaletteId->blockSignals(true);
this->ui->spinBox_PaletteId->setValue(paletteId);
this->refreshColorSliders();
this->refreshColors();
this->ui->spinBox_PaletteId->blockSignals(false);
}
void PaletteEditor::setColor(int colorIndex) {
int paletteNum = this->ui->spinBox_PaletteId->value();
int red = this->sliders[colorIndex][0]->value() * 8;
int green = this->sliders[colorIndex][1]->value() * 8;
int blue = this->sliders[colorIndex][2]->value() * 8;
Tileset *tileset = paletteNum < Project::getNumPalettesPrimary()
? this->primaryTileset
: this->secondaryTileset;
(*tileset->palettes)[paletteNum][colorIndex] = qRgb(red, green, blue);
this->refreshColor(colorIndex);
emit this->changedPaletteColor();
}
void PaletteEditor::on_spinBox_PaletteId_valueChanged(int paletteId) {
this->refreshColorSliders();
this->refreshColors();
emit this->changedPalette(paletteId);
}

View file

@ -0,0 +1,108 @@
#include "selectablepixmapitem.h"
#include <QPainter>
QPoint SelectablePixmapItem::getSelectionDimensions()
{
return QPoint(abs(this->selectionOffsetX) + 1, abs(this->selectionOffsetY) + 1);
}
QPoint SelectablePixmapItem::getSelectionStart()
{
int x = this->selectionInitialX;
int y = this->selectionInitialY;
if (this->selectionOffsetX < 0) x += this->selectionOffsetX;
if (this->selectionOffsetY < 0) y += this->selectionOffsetY;
return QPoint(x, y);
}
void SelectablePixmapItem::select(int x, int y, int width, int height)
{
this->selectionInitialX = x;
this->selectionInitialY = y;
this->selectionOffsetX = qMax(0, qMin(width, this->maxSelectionWidth));
this->selectionOffsetY = qMax(0, qMin(height, this->maxSelectionHeight));
this->draw();
}
void SelectablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPoint pos = this->getCellPos(event->pos());
this->selectionInitialX = pos.x();
this->selectionInitialY = pos.y();
this->selectionOffsetX = 0;
this->selectionOffsetY = 0;
this->updateSelection(pos.x(), pos.y());
}
void SelectablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPoint pos = this->getCellPos(event->pos());
this->updateSelection(pos.x(), pos.y());
}
void SelectablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QPoint pos = this->getCellPos(event->pos());
this->updateSelection(pos.x(), pos.y());
}
void SelectablePixmapItem::updateSelection(int x, int y)
{
// Snap to a valid position inside the selection area.
int width = pixmap().width() / this->cellWidth;
int height = pixmap().height() / this->cellHeight;
if (x < 0) x = 0;
if (x >= width) x = width - 1;
if (y < 0) y = 0;
if (y >= height) y = height - 1;
this->selectionOffsetX = x - this->selectionInitialX;
this->selectionOffsetY = y - this->selectionInitialY;
// Respect max selection dimensions by moving the selection's origin.
if (this->selectionOffsetX >= this->maxSelectionWidth) {
this->selectionInitialX += this->selectionOffsetX - this->maxSelectionWidth + 1;
this->selectionOffsetX = this->maxSelectionWidth - 1;
} else if (this->selectionOffsetX <= -this->maxSelectionWidth) {
this->selectionInitialX += this->selectionOffsetX + this->maxSelectionWidth - 1;
this->selectionOffsetX = -this->maxSelectionWidth + 1;
}
if (this->selectionOffsetY >= this->maxSelectionHeight) {
this->selectionInitialY += this->selectionOffsetY - this->maxSelectionHeight + 1;
this->selectionOffsetY = this->maxSelectionHeight - 1;
} else if (this->selectionOffsetY <= -this->maxSelectionHeight) {
this->selectionInitialY += this->selectionOffsetY + this->maxSelectionHeight - 1;
this->selectionOffsetY = -this->maxSelectionHeight + 1;
}
this->draw();
}
QPoint SelectablePixmapItem::getCellPos(QPointF pos)
{
if (pos.x() < 0) pos.setX(0);
if (pos.y() < 0) pos.setY(0);
if (pos.x() >= this->pixmap().width()) pos.setX(this->pixmap().width() - 1);
if (pos.y() >= this->pixmap().height()) pos.setY(this->pixmap().height() - 1);
return QPoint(static_cast<int>(pos.x()) / this->cellWidth,
static_cast<int>(pos.y()) / this->cellHeight);
}
void SelectablePixmapItem::drawSelection()
{
QPixmap pixmap = this->pixmap();
QPainter painter(&pixmap);
QPoint origin = this->getSelectionStart();
QPoint dimensions = this->getSelectionDimensions();
int rectWidth = dimensions.x() * this->cellWidth;
int rectHeight = dimensions.y() * this->cellHeight;
painter.setPen(QColor(0xff, 0xff, 0xff));
painter.drawRect(origin.x() * this->cellWidth, origin.y() * this->cellHeight, rectWidth - 1, rectHeight -1);
painter.setPen(QColor(0, 0, 0));
painter.drawRect(origin.x() * this->cellWidth - 1, origin.y() * this->cellHeight - 1, rectWidth + 1, rectHeight + 1);
painter.drawRect(origin.x() * this->cellWidth + 1, origin.y() * this->cellHeight + 1, rectWidth - 3, rectHeight - 3);
this->setPixmap(pixmap);
}

460
src/ui/tileseteditor.cpp Normal file
View file

@ -0,0 +1,460 @@
#include "tileseteditor.h"
#include "ui_tileseteditor.h"
#include "imageproviders.h"
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include <QDialogButtonBox>
TilesetEditor::TilesetEditor(Project *project, QString primaryTilesetLabel, QString secondaryTilesetLabel, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TilesetEditor)
{
this->init(project, primaryTilesetLabel, secondaryTilesetLabel);
}
TilesetEditor::~TilesetEditor()
{
delete ui;
}
void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString secondaryTilesetLabel) {
ui->setupUi(this);
this->project = project;
this->hasUnsavedChanges = false;
this->tileXFlip = ui->checkBox_xFlip->isChecked();
this->tileYFlip = ui->checkBox_yFlip->isChecked();
this->paletteId = ui->spinBox_paletteSelector->value();
Tileset *primaryTileset = project->getTileset(primaryTilesetLabel);
Tileset *secondaryTileset = project->getTileset(secondaryTilesetLabel);
if (this->primaryTileset) delete this->primaryTileset;
if (this->secondaryTileset) delete this->secondaryTileset;
this->primaryTileset = primaryTileset->copy();
this->secondaryTileset = secondaryTileset->copy();
QList<QString> sortedBehaviors;
for (int num : project->metatileBehaviorMapInverse.keys()) {
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
}
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", 0);
this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", 1);
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", 2);
this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
this->initMetatileSelector();
this->initMetatileLayersItem();
this->initTileSelector();
this->initSelectedTileItem();
this->metatileSelector->select(0);
}
void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
delete this->primaryTileset;
delete this->secondaryTileset;
Tileset *primaryTileset = project->getTileset(primaryTilesetLabel);
Tileset *secondaryTileset = project->getTileset(secondaryTilesetLabel);
this->primaryTileset = primaryTileset->copy();
this->secondaryTileset = secondaryTileset->copy();
this->refresh();
}
void TilesetEditor::refresh() {
this->metatileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
this->tileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
this->metatileLayersItem->setTilesets(this->primaryTileset, this->secondaryTileset);
this->metatileSelector->select(this->metatileSelector->getSelectedMetatile());
this->drawSelectedTiles();
this->ui->graphicsView_Tiles->setSceneRect(0, 0, this->tileSelector->pixmap().width() + 2, this->tileSelector->pixmap().height() + 2);
this->ui->graphicsView_Tiles->setFixedSize(this->tileSelector->pixmap().width() + 2, this->tileSelector->pixmap().height() + 2);
this->ui->graphicsView_Metatiles->setSceneRect(0, 0, this->metatileSelector->pixmap().width() + 2, this->metatileSelector->pixmap().height() + 2);
this->ui->graphicsView_Metatiles->setFixedSize(this->metatileSelector->pixmap().width() + 2, this->metatileSelector->pixmap().height() + 2);
this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width(), this->selectedTilePixmapItem->pixmap().height());
}
void TilesetEditor::initMetatileSelector()
{
this->metatileSelector = new TilesetEditorMetatileSelector(this->primaryTileset, this->secondaryTileset);
connect(this->metatileSelector, SIGNAL(hoveredMetatileChanged(uint16_t)),
this, SLOT(onHoveredMetatileChanged(uint16_t)));
connect(this->metatileSelector, SIGNAL(hoveredMetatileCleared()),
this, SLOT(onHoveredMetatileCleared()));
connect(this->metatileSelector, SIGNAL(selectedMetatileChanged(uint16_t)),
this, SLOT(onSelectedMetatileChanged(uint16_t)));
this->metatilesScene = new QGraphicsScene;
this->metatilesScene->addItem(this->metatileSelector);
this->metatileSelector->draw();
this->ui->graphicsView_Metatiles->setScene(this->metatilesScene);
this->ui->graphicsView_Metatiles->setFixedSize(this->metatileSelector->pixmap().width() + 2, this->metatileSelector->pixmap().height() + 2);
}
void TilesetEditor::initTileSelector()
{
this->tileSelector = new TilesetEditorTileSelector(this->primaryTileset, this->secondaryTileset);
connect(this->tileSelector, SIGNAL(hoveredTileChanged(uint16_t)),
this, SLOT(onHoveredTileChanged(uint16_t)));
connect(this->tileSelector, SIGNAL(hoveredTileCleared()),
this, SLOT(onHoveredTileCleared()));
connect(this->tileSelector, SIGNAL(selectedTilesChanged()),
this, SLOT(onSelectedTilesChanged()));
this->tilesScene = new QGraphicsScene;
this->tilesScene->addItem(this->tileSelector);
this->tileSelector->select(0);
this->tileSelector->draw();
this->ui->graphicsView_Tiles->setScene(this->tilesScene);
this->ui->graphicsView_Tiles->setFixedSize(this->tileSelector->pixmap().width() + 2, this->tileSelector->pixmap().height() + 2);
}
void TilesetEditor::initSelectedTileItem() {
this->selectedTileScene = new QGraphicsScene;
this->drawSelectedTiles();
this->ui->graphicsView_selectedTile->setScene(this->selectedTileScene);
this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width(), this->selectedTilePixmapItem->pixmap().height());
}
void TilesetEditor::drawSelectedTiles() {
if (!this->selectedTileScene) {
return;
}
this->selectedTileScene->clear();
QList<uint16_t> tiles = this->tileSelector->getSelectedTiles();
QPoint dimensions = this->tileSelector->getSelectionDimensions();
QImage selectionImage(16 * dimensions.x(), 16 * dimensions.y(), QImage::Format_RGBA8888);
QPainter painter(&selectionImage);
int tileIndex = 0;
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
QImage tileImage = getColoredTileImage(tiles.at(tileIndex), this->primaryTileset, this->secondaryTileset, this->paletteId)
.mirrored(this->tileXFlip, this->tileYFlip)
.scaled(16, 16);
tileIndex++;
painter.drawImage(i * 16, j * 16, tileImage);
}
}
this->selectedTilePixmapItem = new QGraphicsPixmapItem(QPixmap::fromImage(selectionImage));
this->selectedTileScene->addItem(this->selectedTilePixmapItem);
this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width(), this->selectedTilePixmapItem->pixmap().height());
}
void TilesetEditor::initMetatileLayersItem() {
Metatile *metatile = Tileset::getMetatile(this->metatileSelector->getSelectedMetatile(), this->primaryTileset, this->secondaryTileset);
this->metatileLayersItem = new MetatileLayersItem(metatile, this->primaryTileset, this->secondaryTileset);
connect(this->metatileLayersItem, SIGNAL(tileChanged(int, int)),
this, SLOT(onMetatileLayerTileChanged(int, int)));
this->metatileLayersScene = new QGraphicsScene;
this->metatileLayersScene->addItem(this->metatileLayersItem);
this->ui->graphicsView_metatileLayers->setScene(this->metatileLayersScene);
}
void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) {
QString message = QString("Metatile: 0x%1")
.arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper());
this->ui->statusbar->showMessage(message);
}
void TilesetEditor::onHoveredMetatileCleared() {
this->ui->statusbar->clearMessage();
}
void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
this->metatile = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
this->metatileLayersItem->setMetatile(metatile);
this->metatileLayersItem->draw();
this->ui->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior));
this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType));
}
void TilesetEditor::onHoveredTileChanged(uint16_t tile) {
QString message = QString("Tile: 0x%1")
.arg(QString("%1").arg(tile, 3, 16, QChar('0')).toUpper());
this->ui->statusbar->showMessage(message);
}
void TilesetEditor::onHoveredTileCleared() {
this->ui->statusbar->clearMessage();
}
void TilesetEditor::onSelectedTilesChanged() {
this->drawSelectedTiles();
}
void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
int maxTileIndex = x < 2 ? 3 : 7;
QPoint dimensions = this->tileSelector->getSelectionDimensions();
QList<uint16_t> tiles = this->tileSelector->getSelectedTiles();
int selectedTileIndex = 0;
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
int tileIndex = ((x + i) / 2 * 4) + ((y + j) * 2) + ((x + i) % 2);
if (tileIndex <= maxTileIndex) {
Tile tile = this->metatile->tiles->at(tileIndex);
tile.tile = tiles.at(selectedTileIndex);
tile.xflip = this->tileXFlip;
tile.yflip = this->tileYFlip;
tile.palette = this->paletteId;
(*this->metatile->tiles)[tileIndex] = tile;
}
selectedTileIndex++;
}
}
this->metatileSelector->draw();
this->metatileLayersItem->draw();
this->hasUnsavedChanges = true;
}
void TilesetEditor::on_spinBox_paletteSelector_valueChanged(int paletteId)
{
this->ui->spinBox_paletteSelector->blockSignals(true);
this->ui->spinBox_paletteSelector->setValue(paletteId);
this->ui->spinBox_paletteSelector->blockSignals(false);
this->paletteId = paletteId;
this->tileSelector->setPaletteId(paletteId);
this->drawSelectedTiles();
if (this->paletteEditor) {
this->paletteEditor->setPaletteId(paletteId);
}
}
void TilesetEditor::on_checkBox_xFlip_stateChanged(int checked)
{
this->tileXFlip = checked;
this->tileSelector->setTileFlips(this->tileXFlip, this->tileYFlip);
this->drawSelectedTiles();
}
void TilesetEditor::on_checkBox_yFlip_stateChanged(int checked)
{
this->tileYFlip = checked;
this->tileSelector->setTileFlips(this->tileXFlip, this->tileYFlip);
this->drawSelectedTiles();
}
void TilesetEditor::on_comboBox_metatileBehaviors_currentIndexChanged(const QString &metatileBehavior)
{
if (this->metatile) {
this->metatile->behavior = static_cast<uint8_t>(project->metatileBehaviorMap[metatileBehavior]);
}
}
void TilesetEditor::on_comboBox_layerType_currentIndexChanged(int layerType)
{
if (this->metatile) {
this->metatile->layerType = static_cast<uint8_t>(layerType);
}
}
void TilesetEditor::on_actionSave_Tileset_triggered()
{
this->project->saveTilesets(this->primaryTileset, this->secondaryTileset);
emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name);
this->ui->statusbar->showMessage(QString("Saved primary and secondary Tilesets!"), 5000);
this->hasUnsavedChanges = false;
}
void TilesetEditor::on_actionImport_Primary_Tiles_triggered()
{
this->importTilesetTiles(this->primaryTileset, true);
}
void TilesetEditor::on_actionImport_Secondary_Tiles_triggered()
{
this->importTilesetTiles(this->secondaryTileset, false);
}
void TilesetEditor::importTilesetTiles(Tileset *tileset, bool primary) {
QString descriptor = primary ? "primary" : "secondary";
QString descriptorCaps = primary ? "Primary" : "Secondary";
QString filepath = QFileDialog::getOpenFileName(
this,
QString("Import %1 Tileset Tiles Image").arg(descriptorCaps),
this->project->root,
"Image Files (*.png)");
if (filepath.isEmpty()) {
return;
}
qDebug() << QString("Importing %1 tileset tiles '%2'").arg(descriptor).arg(filepath);
// Validate image dimensions.
QImage image = QImage(filepath);
if (image.width() == 0 || image.height() == 0 || image.width() % 8 != 0 || image.height() % 8 != 0) {
QMessageBox msgBox(this);
msgBox.setText("Failed to import tiles.");
msgBox.setInformativeText(QString("The image dimensions (%1 x %2) are invalid. Width and height must be multiples of 8 pixels.")
.arg(image.width())
.arg(image.height()));
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Icon::Critical);
msgBox.exec();
return;
}
// Validate image is properly indexed to 16 colors.
if (image.colorCount() != 16) {
QMessageBox msgBox(this);
msgBox.setText("Failed to import tiles.");
msgBox.setInformativeText(QString("The image must be indexed and contain 16 total colors. The provided image has %1 indexed colors.")
.arg(image.colorCount()));
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Icon::Critical);
msgBox.exec();
return;
}
// Validate total number of tiles in image.
int numTilesWide = image.width() / 16;
int numTilesHigh = image.height() / 16;
int totalTiles = numTilesHigh * numTilesWide;
int maxAllowedTiles = primary ? Project::getNumTilesPrimary() : Project::getNumTilesTotal() - Project::getNumTilesPrimary();
if (totalTiles > maxAllowedTiles) {
QMessageBox msgBox(this);
msgBox.setText("Failed to import tiles.");
msgBox.setInformativeText(QString("The maximum number of tiles allowed in the %1 tileset is %2, but the provided image contains %3 total tiles.")
.arg(descriptor)
.arg(maxAllowedTiles)
.arg(totalTiles));
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Icon::Critical);
msgBox.exec();
return;
}
this->project->loadTilesetTiles(tileset, image);
this->project->loadTilesetMetatiles(tileset);
this->refresh();
this->hasUnsavedChanges = true;
}
void TilesetEditor::closeEvent(QCloseEvent *event)
{
bool close = true;
if (this->hasUnsavedChanges) {
QMessageBox::StandardButton result = QMessageBox::question(this, "porymap",
"Discard unsaved Tileset changes?",
QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
close = result == QMessageBox::Yes;
}
if (close) {
event->accept();
emit closed();
} else {
event->ignore();
}
}
void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
{
QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
dialog.setWindowTitle("Change Number of Metatiles");
dialog.setWindowModality(Qt::NonModal);
QFormLayout form(&dialog);
QSpinBox *primarySpinBox = new QSpinBox();
QSpinBox *secondarySpinBox = new QSpinBox();
primarySpinBox->setMinimum(1);
secondarySpinBox->setMinimum(1);
primarySpinBox->setMaximum(Project::getNumMetatilesPrimary());
secondarySpinBox->setMaximum(Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary());
primarySpinBox->setValue(this->primaryTileset->metatiles->length());
secondarySpinBox->setValue(this->secondaryTileset->metatiles->length());
form.addRow(new QLabel("Primary Tileset"), primarySpinBox);
form.addRow(new QLabel("Secondary Tileset"), secondarySpinBox);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
form.addRow(&buttonBox);
if (dialog.exec() == QDialog::Accepted) {
int numPrimaryMetatiles = primarySpinBox->value();
int numSecondaryMetatiles = secondarySpinBox->value();
while (this->primaryTileset->metatiles->length() > numPrimaryMetatiles) {
Metatile *metatile = this->primaryTileset->metatiles->takeLast();
delete metatile;
}
while (this->primaryTileset->metatiles->length() < numPrimaryMetatiles) {
Tile tile;
tile.palette = 0;
tile.tile = 0;
tile.xflip = 0;
tile.yflip = 0;
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}
this->primaryTileset->metatiles->append(metatile);
}
while (this->secondaryTileset->metatiles->length() > numSecondaryMetatiles) {
Metatile *metatile = this->secondaryTileset->metatiles->takeLast();
delete metatile;
}
while (this->secondaryTileset->metatiles->length() < numSecondaryMetatiles) {
Tile tile;
tile.palette = 0;
tile.tile = 0;
tile.xflip = 0;
tile.yflip = 0;
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}
this->secondaryTileset->metatiles->append(metatile);
}
this->refresh();
this->hasUnsavedChanges = true;
}
}
void TilesetEditor::onPaletteEditorClosed() {
if (this->paletteEditor) {
delete this->paletteEditor;
this->paletteEditor = nullptr;
}
}
void TilesetEditor::on_actionChange_Palettes_triggered()
{
if (!this->paletteEditor) {
this->paletteEditor = new PaletteEditor(this->project, this->primaryTileset, this->secondaryTileset, this);
connect(this->paletteEditor, SIGNAL(closed()), this, SLOT(onPaletteEditorClosed()));
connect(this->paletteEditor, SIGNAL(changedPaletteColor()), this, SLOT(onPaletteEditorChangedPaletteColor()));
connect(this->paletteEditor, SIGNAL(changedPalette(int)), this, SLOT(onPaletteEditorChangedPalette(int)));
}
if (!this->paletteEditor->isVisible()) {
this->paletteEditor->show();
} else if (this->paletteEditor->isMinimized()) {
this->paletteEditor->showNormal();
} else {
this->paletteEditor->activateWindow();
}
}
void TilesetEditor::onPaletteEditorChangedPaletteColor() {
this->refresh();
this->hasUnsavedChanges = true;
}
void TilesetEditor::onPaletteEditorChangedPalette(int paletteId) {
this->on_spinBox_paletteSelector_valueChanged(paletteId);
}

View file

@ -0,0 +1,114 @@
#include "tileseteditormetatileselector.h"
#include "imageproviders.h"
#include "project.h"
#include <QPainter>
void TilesetEditorMetatileSelector::draw() {
if (!this->primaryTileset || !this->primaryTileset->metatiles
|| !this->secondaryTileset || !this->secondaryTileset->metatiles) {
this->setPixmap(QPixmap());
}
int primaryLength = this->primaryTileset->metatiles->length();
int length_ = primaryLength + this->secondaryTileset->metatiles->length();
int height_ = length_ / this->numMetatilesWide;
QImage image(this->numMetatilesWide * 32, height_ * 32, QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < length_; i++) {
int tile = i;
if (i >= primaryLength) {
tile += Project::getNumMetatilesPrimary() - primaryLength;
}
QImage metatile_image = getMetatileImage(tile, this->primaryTileset, this->secondaryTileset).scaled(32, 32);
int map_y = i / this->numMetatilesWide;
int map_x = i % this->numMetatilesWide;
QPoint metatile_origin = QPoint(map_x * 32, map_y * 32);
painter.drawImage(metatile_origin, metatile_image);
}
painter.end();
this->setPixmap(QPixmap::fromImage(image));
this->drawSelection();
}
void TilesetEditorMetatileSelector::select(uint16_t metatileId) {
metatileId = this->getValidMetatileId(metatileId);
QPoint coords = this->getMetatileIdCoords(metatileId);
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
this->selectedMetatile = metatileId;
emit selectedMetatileChanged(metatileId);
}
void TilesetEditorMetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->draw();
}
void TilesetEditorMetatileSelector::updateSelectedMetatile() {
QPoint origin = this->getSelectionStart();
this->selectedMetatile = this->getMetatileId(origin.x(), origin.y());
}
uint16_t TilesetEditorMetatileSelector::getSelectedMetatile() {
return this->selectedMetatile;
}
uint16_t TilesetEditorMetatileSelector::getMetatileId(int x, int y) {
int index = y * this->numMetatilesWide + x;
if (index < this->primaryTileset->metatiles->length()) {
return static_cast<uint16_t>(index);
} else {
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - this->primaryTileset->metatiles->length());
}
}
void TilesetEditorMetatileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedMetatile();
emit selectedMetatileChanged(this->selectedMetatile);
}
void TilesetEditorMetatileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseMoveEvent(event);
this->updateSelectedMetatile();
QPoint pos = this->getCellPos(event->pos());
uint16_t metatileId = this->getMetatileId(pos.x(), pos.y());
emit hoveredMetatileChanged(metatileId);
emit selectedMetatileChanged(metatileId);
}
void TilesetEditorMetatileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseReleaseEvent(event);
this->updateSelectedMetatile();
emit selectedMetatileChanged(this->selectedMetatile);
}
void TilesetEditorMetatileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
QPoint pos = this->getCellPos(event->pos());
uint16_t metatileId = this->getMetatileId(pos.x(), pos.y());
emit this->hoveredMetatileChanged(metatileId);
}
void TilesetEditorMetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
emit this->hoveredMetatileCleared();
}
QPoint TilesetEditorMetatileSelector::getMetatileIdCoords(uint16_t metatileId) {
int index = metatileId < Project::getNumMetatilesPrimary()
? metatileId
: metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->metatiles->length();
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
}
uint16_t TilesetEditorMetatileSelector::getValidMetatileId(uint16_t metatileId) {
if (metatileId >= Project::getNumMetatilesTotal()
|| (metatileId < Project::getNumMetatilesPrimary() && metatileId >= this->primaryTileset->metatiles->length())
|| (metatileId < Project::getNumMetatilesTotal() && metatileId >= Project::getNumMetatilesPrimary() + this->secondaryTileset->metatiles->length()))
{
return 0;
}
return metatileId;
}

View file

@ -0,0 +1,130 @@
#include "tileseteditortileselector.h"
#include "imageproviders.h"
#include "project.h"
#include <QPainter>
void TilesetEditorTileSelector::draw() {
if (!this->primaryTileset || !this->primaryTileset->tiles
|| !this->secondaryTileset || !this->secondaryTileset->tiles) {
this->setPixmap(QPixmap());
}
int totalTiles = Project::getNumTilesTotal();
int primaryLength = this->primaryTileset->tiles->length();
int secondaryLength = this->secondaryTileset->tiles->length();
int height = totalTiles / this->numTilesWide;
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset);
QImage image(this->numTilesWide * 16, height * 16, QImage::Format_RGBA8888);
QPainter painter(&image);
for (uint16_t tile = 0; tile < totalTiles; tile++) {
QImage tileImage;
if (tile < primaryLength) {
tileImage = getColoredTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId).scaled(16, 16);
} else if (tile < Project::getNumTilesPrimary()) {
tileImage = QImage(16, 16, QImage::Format_RGBA8888);
tileImage.fill(palette.at(0));
} else if (tile < Project::getNumTilesPrimary() + secondaryLength) {
tileImage = getColoredTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId).scaled(16, 16);
} else {
tileImage = QImage(16, 16, QImage::Format_RGBA8888);
QPainter painter(&tileImage);
painter.fillRect(0, 0, 16, 16, palette.at(0));
}
int y = tile / this->numTilesWide;
int x = tile % this->numTilesWide;
QPoint origin = QPoint(x * 16, y * 16);
painter.drawImage(origin, tileImage.mirrored(this->xFlip, this->yFlip));
}
painter.end();
this->setPixmap(QPixmap::fromImage(image));
this->drawSelection();
}
void TilesetEditorTileSelector::select(uint16_t tile) {
QPoint coords = this->getTileCoords(tile);
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
this->updateSelectedTiles();
emit selectedTilesChanged();
}
void TilesetEditorTileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->draw();
}
void TilesetEditorTileSelector::setPaletteId(int paletteId) {
this->paletteId = paletteId;
this->draw();
}
void TilesetEditorTileSelector::setTileFlips(bool xFlip, bool yFlip) {
this->xFlip = xFlip;
this->yFlip = yFlip;
this->draw();
}
void TilesetEditorTileSelector::updateSelectedTiles() {
this->selectedTiles.clear();
QPoint origin = this->getSelectionStart();
QPoint dimensions = this->getSelectionDimensions();
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
uint16_t metatileId = this->getTileId(origin.x() + i, origin.y() + j);
this->selectedTiles.append(metatileId);
}
}
}
QList<uint16_t> TilesetEditorTileSelector::getSelectedTiles() {
return this->selectedTiles;
}
uint16_t TilesetEditorTileSelector::getTileId(int x, int y) {
return static_cast<uint16_t>(y * this->numTilesWide + x);
}
void TilesetEditorTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mousePressEvent(event);
this->updateSelectedTiles();
emit selectedTilesChanged();
}
void TilesetEditorTileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseMoveEvent(event);
this->updateSelectedTiles();
QPoint pos = this->getCellPos(event->pos());
uint16_t tile = this->getTileId(pos.x(), pos.y());
emit hoveredTileChanged(tile);
emit selectedTilesChanged();
}
void TilesetEditorTileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
SelectablePixmapItem::mouseReleaseEvent(event);
this->updateSelectedTiles();
emit selectedTilesChanged();
}
void TilesetEditorTileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
QPoint pos = this->getCellPos(event->pos());
uint16_t tile = this->getTileId(pos.x(), pos.y());
emit this->hoveredTileChanged(tile);
}
void TilesetEditorTileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
emit this->hoveredTileCleared();
}
QPoint TilesetEditorTileSelector::getTileCoords(uint16_t tile) {
if (tile >= Project::getNumTilesTotal())
{
// Invalid tile.
return QPoint(0, 0);
}
return QPoint(tile % this->numTilesWide, tile / this->numTilesWide);
}

View file

@ -1,116 +0,0 @@
#include "tileset.h"
#include "project.h"
#include <QPainter>
#include <QImage>
#include <QDebug>
Tileset::Tileset()
{
}
Metatile::Metatile()
{
tiles = new QList<Tile>;
}
QImage Metatile::getMetatileImage(int tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
Metatile* metatile = Metatile::getMetatile(tile, primaryTileset, secondaryTileset);
if (!metatile || !metatile->tiles) {
metatile_image.fill(0xffffffff);
return metatile_image;
}
Tileset* blockTileset = Metatile::getBlockTileset(tile, primaryTileset, secondaryTileset);
if (!blockTileset) {
metatile_image.fill(0xffffffff);
return metatile_image;
}
QList<QList<QRgb>> palettes = Metatile::getBlockPalettes(primaryTileset, secondaryTileset);
QPainter metatile_painter(&metatile_image);
for (int layer = 0; layer < 2; layer++)
for (int y = 0; y < 2; y++)
for (int x = 0; x < 2; x++) {
Tile tile_ = metatile->tiles->value((y * 2) + x + (layer * 4));
QImage tile_image = Metatile::getMetatileTile(tile_.tile, primaryTileset, secondaryTileset);
if (tile_image.isNull()) {
// Some metatiles specify tiles that are outside the valid range.
// These are treated as completely transparent, so they can be skipped without
// being drawn.
continue;
}
// Colorize the metatile tiles with its palette.
if (tile_.palette < palettes.length()) {
QList<QRgb> palette = palettes.value(tile_.palette);
for (int j = 0; j < palette.length(); j++) {
tile_image.setColor(j, palette.value(j));
}
} else {
qDebug() << "Tile is referring to invalid palette number: " << tile_.palette;
}
// The top layer of the metatile has its first color displayed at transparent.
if (layer > 0) {
QColor color(tile_image.color(0));
color.setAlpha(0);
tile_image.setColor(0, color.rgba());
}
QPoint origin = QPoint(x*8, y*8);
metatile_painter.drawImage(origin, tile_image.mirrored(tile_.xflip == 1, tile_.yflip == 1));
}
metatile_painter.end();
return metatile_image;
}
Metatile* Metatile::getMetatile(int index, Tileset *primaryTileset, Tileset *secondaryTileset) {
Tileset *tileset = Metatile::getBlockTileset(index, primaryTileset, secondaryTileset);
int local_index = Metatile::getBlockIndex(index);
if (!tileset || !tileset->metatiles) {
return nullptr;
}
Metatile *metatile = tileset->metatiles->value(local_index, nullptr);
return metatile;
}
QImage Metatile::getMetatileTile(int tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
Tileset *tileset = Metatile::getBlockTileset(tile, primaryTileset, secondaryTileset);
int local_index = Metatile::getBlockIndex(tile);
if (!tileset || !tileset->tiles) {
return QImage();
}
return tileset->tiles->value(local_index, QImage());
}
Tileset* Metatile::getBlockTileset(int metatile_index, Tileset *primaryTileset, Tileset *secondaryTileset) {
if (metatile_index < Project::getNumMetatilesPrimary()) {
return primaryTileset;
} else {
return secondaryTileset;
}
}
int Metatile::getBlockIndex(int index) {
if (index < Project::getNumMetatilesPrimary()) {
return index;
} else {
return index - Project::getNumMetatilesPrimary();
}
}
QList<QList<QRgb>> Metatile::getBlockPalettes(Tileset *primaryTileset, Tileset *secondaryTileset) {
QList<QList<QRgb>> palettes;
for (int i = 0; i < Project::getNumPalettesPrimary(); i++) {
palettes.append(primaryTileset->palettes->at(i));
}
for (int i = Project::getNumPalettesPrimary(); i < Project::getNumPalettesTotal(); i++) {
palettes.append(secondaryTileset->palettes->at(i));
}
return palettes;
}