mirror of
https://github.com/huderlem/porymap.git
synced 2026-06-22 15:49:47 -05:00
Merge pull request #719 from GriffinRichards/local-id
Support local ID strings, misc event fixes
This commit is contained in:
commit
f776a31e4a
|
|
@ -14,7 +14,7 @@ class Map;
|
|||
class Layout;
|
||||
class Blockdata;
|
||||
class Event;
|
||||
class DraggablePixmapItem;
|
||||
class EventPixmapItem;
|
||||
class Editor;
|
||||
|
||||
enum CommandId {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class EventFrame;
|
|||
class ObjectFrame;
|
||||
class CloneObjectFrame;
|
||||
class WarpFrame;
|
||||
class DraggablePixmapItem;
|
||||
class EventPixmapItem;
|
||||
|
||||
class Event;
|
||||
class ObjectEvent;
|
||||
|
|
@ -79,9 +79,13 @@ public:
|
|||
None,
|
||||
};
|
||||
|
||||
// all event groups except warps have IDs that start at 1
|
||||
// Normally we refer to events using their index in the list of that group's events.
|
||||
// Object events often get referred to with a special "local ID", which is really just the index + 1.
|
||||
// We use this local ID number in the index spinner for object events instead of the actual index.
|
||||
// This distinction is only really important for object and warp events, because these are normally
|
||||
// the only two groups of events that need to be explicitly referred to.
|
||||
static int getIndexOffset(Event::Group group) {
|
||||
return (group == Event::Group::Warp) ? 0 : 1;
|
||||
return (group == Event::Group::Object) ? 1 : 0;
|
||||
}
|
||||
|
||||
static Event::Group typeToGroup(Event::Type type) {
|
||||
|
|
@ -149,13 +153,13 @@ public:
|
|||
QJsonObject getCustomAttributes() const { return this->customAttributes; }
|
||||
void setCustomAttributes(const QJsonObject &newCustomAttributes) { this->customAttributes = newCustomAttributes; }
|
||||
|
||||
virtual void loadPixmap(Project *project);
|
||||
virtual QPixmap loadPixmap(Project *project);
|
||||
|
||||
void setPixmap(QPixmap newPixmap) { this->pixmap = newPixmap; }
|
||||
QPixmap getPixmap() const { return this->pixmap; }
|
||||
|
||||
void setPixmapItem(DraggablePixmapItem *item);
|
||||
DraggablePixmapItem *getPixmapItem() const { return this->pixmapItem; }
|
||||
void setPixmapItem(EventPixmapItem *item);
|
||||
EventPixmapItem *getPixmapItem() const { return this->pixmapItem; }
|
||||
|
||||
void setUsesDefaultPixmap(bool newUsesDefaultPixmap) { this->usesDefaultPixmap = newUsesDefaultPixmap; }
|
||||
bool getUsesDefaultPixmap() const { return this->usesDefaultPixmap; }
|
||||
|
|
@ -194,7 +198,7 @@ protected:
|
|||
QJsonObject customAttributes;
|
||||
|
||||
QPixmap pixmap;
|
||||
DraggablePixmapItem *pixmapItem = nullptr;
|
||||
EventPixmapItem *pixmapItem = nullptr;
|
||||
|
||||
QPointer<EventFrame> eventFrame;
|
||||
|
||||
|
|
@ -229,7 +233,7 @@ public:
|
|||
|
||||
virtual QSet<QString> getExpectedFields() override;
|
||||
|
||||
virtual void loadPixmap(Project *project) override;
|
||||
virtual QPixmap loadPixmap(Project *project) override;
|
||||
|
||||
void setGfx(QString newGfx) { this->gfx = newGfx; }
|
||||
QString getGfx() const { return this->gfx; }
|
||||
|
|
@ -296,17 +300,17 @@ public:
|
|||
|
||||
virtual QSet<QString> getExpectedFields() override;
|
||||
|
||||
virtual void loadPixmap(Project *project) override;
|
||||
virtual QPixmap loadPixmap(Project *project) override;
|
||||
|
||||
void setTargetMap(QString newTargetMap) { this->targetMap = newTargetMap; }
|
||||
QString getTargetMap() const { return this->targetMap; }
|
||||
|
||||
void setTargetID(int newTargetID) { this->targetID = newTargetID; }
|
||||
int getTargetID() const { return this->targetID; }
|
||||
void setTargetID(QString newTargetID) { this->targetID = newTargetID; }
|
||||
QString getTargetID() const { return this->targetID; }
|
||||
|
||||
private:
|
||||
QString targetMap;
|
||||
int targetID = 0;
|
||||
QString targetID;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ public:
|
|||
void resetEvents();
|
||||
QList<Event *> getEvents(Event::Group group = Event::Group::None) const;
|
||||
Event* getEvent(Event::Group group, int index) const;
|
||||
Event* getEvent(Event::Group group, const QString &idName) const;
|
||||
QStringList getEventIdNames(Event::Group group) const;
|
||||
int getNumEvents(Event::Group group = Event::Group::None) const;
|
||||
QStringList getScriptLabels(Event::Group group = Event::Group::None);
|
||||
QString getScriptsFilePath() const;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include "mapruler.h"
|
||||
#include "encountertablemodel.h"
|
||||
|
||||
class DraggablePixmapItem;
|
||||
class EventPixmapItem;
|
||||
class MetatilesPixmapItem;
|
||||
|
||||
class Editor : public QObject
|
||||
|
|
@ -109,7 +109,7 @@ public:
|
|||
void toggleBorderVisibility(bool visible, bool enableScriptCallback = true);
|
||||
void updateCustomMapAttributes();
|
||||
|
||||
DraggablePixmapItem *addEventPixmapItem(Event *event);
|
||||
EventPixmapItem *addEventPixmapItem(Event *event);
|
||||
void removeEventPixmapItem(Event *event);
|
||||
bool canAddEvents(const QList<Event*> &events);
|
||||
void selectMapEvent(Event *event, bool toggle = false);
|
||||
|
|
@ -118,13 +118,16 @@ public:
|
|||
void duplicateSelectedEvents();
|
||||
void redrawAllEvents();
|
||||
void redrawEvents(const QList<Event*> &events);
|
||||
void redrawEventPixmapItem(DraggablePixmapItem *item);
|
||||
void redrawEventPixmapItem(EventPixmapItem *item);
|
||||
void updateEventPixmapItemZValue(EventPixmapItem *item);
|
||||
qreal getEventOpacity(const Event *event) const;
|
||||
|
||||
void setPlayerViewRect(const QRectF &rect);
|
||||
void updateCursorRectPos(int x, int y);
|
||||
void setCursorRectVisible(bool visible);
|
||||
|
||||
void onEventDragged(Event *event, const QPoint &oldPosition, const QPoint &newPosition);
|
||||
void onEventReleased(Event *event, const QPoint &position);
|
||||
void updateWarpEventWarning(Event *event);
|
||||
void updateWarpEventWarnings();
|
||||
|
||||
|
|
@ -175,10 +178,7 @@ public:
|
|||
static QList<QList<const QImage*>> collisionIcons;
|
||||
|
||||
int eventShiftActionId = 0;
|
||||
|
||||
void eventsView_onMousePress(QMouseEvent *event);
|
||||
|
||||
bool selectingEvent = false;
|
||||
int eventMoveActionId = 0;
|
||||
|
||||
void deleteSelectedEvents();
|
||||
void shouldReselectEvents();
|
||||
|
|
@ -186,6 +186,22 @@ public:
|
|||
static void openInTextEditor(const QString &path, int lineNum = 0);
|
||||
void setCollisionGraphics();
|
||||
|
||||
enum ZValue {
|
||||
MapBorder = -4,
|
||||
MapConnectionInactive = -3,
|
||||
MapConnectionActive = -2,
|
||||
MapConnectionMask = -1,
|
||||
|
||||
// Event pixmaps set their z value to be their y position on the map.
|
||||
// Their y value is int16_t, so we have enough space to allocate the
|
||||
// full range + 1 for the selected event (which should always be on top).
|
||||
EventMinimum = 1,
|
||||
EventMaximum = EventMinimum + 0x10000,
|
||||
|
||||
Ruler,
|
||||
ResizeLayoutPopup
|
||||
};
|
||||
|
||||
public slots:
|
||||
void openMapScripts() const;
|
||||
void openScript(const QString &scriptLabel) const;
|
||||
|
|
@ -253,11 +269,11 @@ private slots:
|
|||
|
||||
signals:
|
||||
void eventsChanged();
|
||||
void openEventMap(Event*);
|
||||
void openConnectedMap(MapConnection*);
|
||||
void wildMonTableOpened(EncounterTableModel*);
|
||||
void wildMonTableClosed();
|
||||
void wildMonTableEdited();
|
||||
void warpEventDoubleClicked(QString, int, Event::Group);
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void tilesetUpdated(QString);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ private slots:
|
|||
void on_action_Save_Project_triggered();
|
||||
bool save(bool currentOnly = false);
|
||||
|
||||
void openWarpMap(QString map_name, int event_id, Event::Group event_group);
|
||||
void openEventMap(Event *event);
|
||||
|
||||
void duplicate();
|
||||
void setClipboardData(poryjson::Json::object);
|
||||
|
|
@ -197,8 +197,7 @@ private slots:
|
|||
void onMapLoaded(Map *map);
|
||||
void onMapRulerStatusChanged(const QString &);
|
||||
void applyUserShortcuts();
|
||||
void markMapEdited();
|
||||
void markSpecificMapEdited(Map*);
|
||||
void markMapEdited(Map*);
|
||||
void markLayoutEdited();
|
||||
|
||||
void on_actionNew_Tileset_triggered();
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
#ifndef DRAGGABLEPIXMAPITEM_H
|
||||
#define DRAGGABLEPIXMAPITEM_H
|
||||
|
||||
#include <QString>
|
||||
#include <QGraphicsItemGroup>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsItemAnimation>
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "events.h"
|
||||
|
||||
class Editor;
|
||||
|
||||
class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {}
|
||||
|
||||
DraggablePixmapItem(Event *event, Editor *editor) : QGraphicsPixmapItem(event->getPixmap()) {
|
||||
this->event = event;
|
||||
event->setPixmapItem(this);
|
||||
this->editor = editor;
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
Event *event = nullptr;
|
||||
|
||||
void updatePosition();
|
||||
void move(int dx, int dy);
|
||||
void moveTo(const QPoint &pos);
|
||||
void emitPositionChanged();
|
||||
void updatePixmap();
|
||||
|
||||
private:
|
||||
Editor *editor = nullptr;
|
||||
QPoint lastPos;
|
||||
bool active = false;
|
||||
bool releaseSelectionQueued = false;
|
||||
|
||||
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(int x) {
|
||||
event->setX(x);
|
||||
updatePosition();
|
||||
}
|
||||
void set_y(int y) {
|
||||
event->setY(y);
|
||||
updatePosition();
|
||||
}
|
||||
void set_elevation(int z) {
|
||||
event->setElevation(z);
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
|
||||
};
|
||||
|
||||
#endif // DRAGGABLEPIXMAPITEM_H
|
||||
|
|
@ -57,7 +57,9 @@ protected:
|
|||
bool initialized = false;
|
||||
bool connected = false;
|
||||
|
||||
void populateDropdown(NoScrollComboBox * combo, const QStringList &items);
|
||||
void populateScriptDropdown(NoScrollComboBox * combo, Project * project);
|
||||
void populateIdNameDropdown(NoScrollComboBox * combo, Project * project, const QString &mapName, Event::Group group);
|
||||
|
||||
private:
|
||||
Event *event;
|
||||
|
|
@ -78,6 +80,7 @@ public:
|
|||
virtual void populate(Project *project) override;
|
||||
|
||||
public:
|
||||
QLineEdit *line_edit_local_id;
|
||||
NoScrollComboBox *combo_sprite;
|
||||
NoScrollComboBox *combo_movement;
|
||||
NoScrollSpinBox *spinner_radius_x;
|
||||
|
|
@ -108,12 +111,15 @@ public:
|
|||
virtual void populate(Project *project) override;
|
||||
|
||||
public:
|
||||
QLineEdit *line_edit_local_id;
|
||||
NoScrollComboBox *combo_sprite;
|
||||
NoScrollSpinBox *spinner_target_id;
|
||||
NoScrollComboBox *combo_target_id;
|
||||
NoScrollComboBox *combo_target_map;
|
||||
|
||||
private:
|
||||
CloneObjectEvent *clone;
|
||||
|
||||
void tryInvalidateIdDropdown(Map *map);
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -131,12 +137,15 @@ public:
|
|||
virtual void populate(Project *project) override;
|
||||
|
||||
public:
|
||||
QLineEdit *line_edit_id;
|
||||
NoScrollComboBox *combo_dest_map;
|
||||
NoScrollComboBox *combo_dest_warp;
|
||||
QPushButton *warning;
|
||||
|
||||
private:
|
||||
WarpEvent *warp;
|
||||
|
||||
void tryInvalidateIdDropdown(Map *map);
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -275,6 +284,8 @@ public:
|
|||
|
||||
private:
|
||||
HealLocationEvent *healLocation;
|
||||
|
||||
void tryInvalidateIdDropdown(Map *map);
|
||||
};
|
||||
|
||||
#endif // EVENTRAMES_H
|
||||
|
|
|
|||
58
include/ui/eventpixmapitem.h
Normal file
58
include/ui/eventpixmapitem.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef EVENTPIXMAPITEM_H
|
||||
#define EVENTPIXMAPITEM_H
|
||||
|
||||
#include <QString>
|
||||
#include <QGraphicsItemGroup>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsItemAnimation>
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include "events.h"
|
||||
|
||||
class Project;
|
||||
|
||||
class EventPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EventPixmapItem(Event *event);
|
||||
|
||||
void render(Project *project);
|
||||
|
||||
bool isSelected() const { return m_selected; }
|
||||
void setSelected(bool selected) { m_selected = selected; }
|
||||
|
||||
Event * getEvent() const { return m_event; }
|
||||
|
||||
void move(int dx, int dy);
|
||||
void moveTo(int x, int y);
|
||||
void moveTo(const QPoint &pos);
|
||||
|
||||
private:
|
||||
QPixmap m_basePixmap;
|
||||
Event *const m_event = nullptr;
|
||||
QPoint m_lastPos;
|
||||
bool m_active = false;
|
||||
bool m_selected = false;
|
||||
bool m_releaseSelectionQueued = false;
|
||||
|
||||
void updatePixelPosition();
|
||||
|
||||
signals:
|
||||
void xChanged(int x);
|
||||
void yChanged(int y);
|
||||
void posChanged(int x, int y);
|
||||
void rendered(const QPixmap &pixmap);
|
||||
void selected(Event *event, bool toggle);
|
||||
void dragged(Event *event, const QPoint &oldPosition, const QPoint &newPosition);
|
||||
void released(Event *event, const QPoint &position);
|
||||
void doubleClicked(Event *event);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override { emit doubleClicked(m_event); }
|
||||
};
|
||||
|
||||
#endif // EVENTPIXMAPITEM_H
|
||||
|
|
@ -45,25 +45,4 @@ protected:
|
|||
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||
};
|
||||
|
||||
class Editor;
|
||||
|
||||
// TODO: This should just be MapView. It makes map-based assumptions, and no other class inherits GraphicsView.
|
||||
class GraphicsView : public QGraphicsView
|
||||
{
|
||||
public:
|
||||
GraphicsView() : QGraphicsView() {}
|
||||
GraphicsView(QWidget *parent) : QGraphicsView(parent) {}
|
||||
|
||||
public:
|
||||
// GraphicsView_Object object;
|
||||
Editor *editor;
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
virtual void moveEvent(QMoveEvent *event) override;
|
||||
};
|
||||
|
||||
//Q_DECLARE_METATYPE(GraphicsView)
|
||||
|
||||
#endif // GRAPHICSVIEW_H
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@
|
|||
#include "graphicsview.h"
|
||||
#include "overlay.h"
|
||||
|
||||
class MapView : public GraphicsView
|
||||
class Editor;
|
||||
|
||||
class MapView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MapView() : GraphicsView() {}
|
||||
MapView(QWidget *parent) : GraphicsView(parent) {}
|
||||
MapView() : QGraphicsView() {}
|
||||
MapView(QWidget *parent) : QGraphicsView(parent) {}
|
||||
|
||||
Editor *editor;
|
||||
|
||||
Overlay * getOverlay(int layer);
|
||||
void clearOverlayMap();
|
||||
|
|
@ -73,6 +77,7 @@ public:
|
|||
protected:
|
||||
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
|
||||
virtual void keyPressEvent(QKeyEvent*) override;
|
||||
virtual void moveEvent(QMoveEvent *event) override;
|
||||
private:
|
||||
QMap<int, Overlay*> overlayMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ SOURCES += src/core/advancemapparser.cpp \
|
|||
src/ui/customscriptseditor.cpp \
|
||||
src/ui/customscriptslistitem.cpp \
|
||||
src/ui/divingmappixmapitem.cpp \
|
||||
src/ui/draggablepixmapitem.cpp \
|
||||
src/ui/eventpixmapitem.cpp \
|
||||
src/ui/bordermetatilespixmapitem.cpp \
|
||||
src/ui/collisionpixmapitem.cpp \
|
||||
src/ui/connectionpixmapitem.cpp \
|
||||
|
|
@ -184,7 +184,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/customscriptseditor.h \
|
||||
include/ui/customscriptslistitem.h \
|
||||
include/ui/divingmappixmapitem.h \
|
||||
include/ui/draggablepixmapitem.h \
|
||||
include/ui/eventpixmapitem.h \
|
||||
include/ui/bordermetatilespixmapitem.h \
|
||||
include/ui/collisionpixmapitem.h \
|
||||
include/ui/connectionpixmapitem.h \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "editcommands.h"
|
||||
#include "draggablepixmapitem.h"
|
||||
#include "eventpixmapitem.h"
|
||||
#include "bordermetatilespixmapitem.h"
|
||||
#include "editor.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ Event* Event::create(Event::Type type) {
|
|||
}
|
||||
|
||||
Event::~Event() {
|
||||
if (this->eventFrame)
|
||||
this->eventFrame->deleteLater();
|
||||
delete this->eventFrame;
|
||||
}
|
||||
|
||||
EventFrame *Event::getEventFrame() {
|
||||
|
|
@ -34,7 +33,7 @@ void Event::destroyEventFrame() {
|
|||
this->eventFrame = nullptr;
|
||||
}
|
||||
|
||||
void Event::setPixmapItem(DraggablePixmapItem *item) {
|
||||
void Event::setPixmapItem(EventPixmapItem *item) {
|
||||
this->pixmapItem = item;
|
||||
if (this->eventFrame) {
|
||||
this->eventFrame->invalidateConnections();
|
||||
|
|
@ -105,7 +104,7 @@ QString Event::typeToString(Event::Type type) {
|
|||
{Event::Type::CloneObject, "Clone Object"},
|
||||
{Event::Type::Warp, "Warp"},
|
||||
{Event::Type::Trigger, "Trigger"},
|
||||
{Event::Type::WeatherTrigger, "Weather"},
|
||||
{Event::Type::WeatherTrigger, "Weather Trigger"},
|
||||
{Event::Type::Sign, "Sign"},
|
||||
{Event::Type::HiddenItem, "Hidden Item"},
|
||||
{Event::Type::SecretBase, "Secret Base"},
|
||||
|
|
@ -114,9 +113,10 @@ QString Event::typeToString(Event::Type type) {
|
|||
return typeToStringMap.value(type);
|
||||
}
|
||||
|
||||
void Event::loadPixmap(Project *project) {
|
||||
QPixmap Event::loadPixmap(Project *project) {
|
||||
this->pixmap = project->getEventPixmap(this->getEventGroup());
|
||||
this->usesDefaultPixmap = true;
|
||||
return this->pixmap;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -152,12 +152,13 @@ EventFrame *ObjectEvent::createEventFrame() {
|
|||
OrderedJson::object ObjectEvent::buildEventJson(Project *) {
|
||||
OrderedJson::object objectJson;
|
||||
|
||||
if (projectConfig.eventCloneObjectEnabled) {
|
||||
objectJson["type"] = Event::typeToJsonKey(Event::Type::Object);
|
||||
}
|
||||
QString idName = this->getIdName();
|
||||
if (!idName.isEmpty())
|
||||
objectJson["local_id"] = idName;
|
||||
|
||||
if (projectConfig.eventCloneObjectEnabled) {
|
||||
objectJson["type"] = Event::typeToJsonKey(Event::Type::Object);
|
||||
}
|
||||
objectJson["graphics_id"] = this->getGfx();
|
||||
objectJson["x"] = this->getX();
|
||||
objectJson["y"] = this->getY();
|
||||
|
|
@ -224,13 +225,13 @@ QSet<QString> ObjectEvent::getExpectedFields() {
|
|||
return expectedFields;
|
||||
}
|
||||
|
||||
void ObjectEvent::loadPixmap(Project *project) {
|
||||
QPixmap ObjectEvent::loadPixmap(Project *project) {
|
||||
this->pixmap = project->getEventPixmap(this->gfx, this->movement);
|
||||
if (!this->pixmap.isNull()) {
|
||||
this->usesDefaultPixmap = false;
|
||||
} else {
|
||||
Event::loadPixmap(project);
|
||||
return this->pixmap;
|
||||
}
|
||||
return Event::loadPixmap(project);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -261,10 +262,11 @@ EventFrame *CloneObjectEvent::createEventFrame() {
|
|||
OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) {
|
||||
OrderedJson::object cloneJson;
|
||||
|
||||
cloneJson["type"] = Event::typeToJsonKey(Event::Type::CloneObject);
|
||||
QString idName = this->getIdName();
|
||||
if (!idName.isEmpty())
|
||||
cloneJson["local_id"] = idName;
|
||||
|
||||
cloneJson["type"] = Event::typeToJsonKey(Event::Type::CloneObject);
|
||||
cloneJson["graphics_id"] = this->getGfx();
|
||||
cloneJson["x"] = this->getX();
|
||||
cloneJson["y"] = this->getY();
|
||||
|
|
@ -281,7 +283,7 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
|
|||
this->setY(readInt(&json, "y"));
|
||||
this->setIdName(readString(&json, "local_id"));
|
||||
this->setGfx(readString(&json, "graphics_id"));
|
||||
this->setTargetID(readInt(&json, "target_local_id"));
|
||||
this->setTargetID(readString(&json, "target_local_id"));
|
||||
|
||||
// Log a warning if "target_map" isn't a known map ID, but don't overwrite user data.
|
||||
const QString mapConstant = readString(&json, "target_map");
|
||||
|
|
@ -295,7 +297,7 @@ bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
|
|||
|
||||
void CloneObjectEvent::setDefaultValues(Project *project) {
|
||||
this->setGfx(project->gfxDefines.key(0, "0"));
|
||||
this->setTargetID(1);
|
||||
this->setTargetID(QString::number(Event::getIndexOffset(Event::Group::Object)));
|
||||
if (this->getMap()) this->setTargetMap(this->getMap()->name());
|
||||
}
|
||||
|
||||
|
|
@ -312,11 +314,10 @@ QSet<QString> CloneObjectEvent::getExpectedFields() {
|
|||
return expectedFields;
|
||||
}
|
||||
|
||||
void CloneObjectEvent::loadPixmap(Project *project) {
|
||||
QPixmap CloneObjectEvent::loadPixmap(Project *project) {
|
||||
// Try to get the targeted object to clone
|
||||
int eventIndex = this->targetID - 1;
|
||||
Map *clonedMap = project->loadMap(this->targetMap);
|
||||
Event *clonedEvent = clonedMap ? clonedMap->getEvent(Event::Group::Object, eventIndex) : nullptr;
|
||||
Event *clonedEvent = clonedMap ? clonedMap->getEvent(Event::Group::Object, this->targetID) : nullptr;
|
||||
|
||||
if (clonedEvent && clonedEvent->getEventType() == Event::Type::Object) {
|
||||
// Get graphics data from cloned object
|
||||
|
|
@ -328,7 +329,7 @@ void CloneObjectEvent::loadPixmap(Project *project) {
|
|||
this->gfx = project->gfxDefines.key(0, "0");
|
||||
this->movement = project->movementTypes.value(0, "0");
|
||||
}
|
||||
ObjectEvent::loadPixmap(project);
|
||||
return ObjectEvent::loadPixmap(project);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,49 @@ Event* Map::getEvent(Event::Group group, int index) const {
|
|||
return m_events[group].value(index, nullptr);
|
||||
}
|
||||
|
||||
Event* Map::getEvent(Event::Group group, const QString &idName) const {
|
||||
if (idName.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
bool idIsNumber;
|
||||
int id = idName.toInt(&idIsNumber, 0);
|
||||
if (idIsNumber)
|
||||
return getEvent(group, id - Event::getIndexOffset(group));
|
||||
|
||||
auto events = getEvents(group);
|
||||
for (const auto &event : events) {
|
||||
if (event->getIdName() == idName) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Returns a list of ID names for the given event group (or all events, if no group is given).
|
||||
// For events with no explicit ID name, their index string is given instead.
|
||||
QStringList Map::getEventIdNames(Event::Group group) const {
|
||||
QList<Event::Group> groups;
|
||||
if (group == Event::Group::None) {
|
||||
groups = Event::groups();
|
||||
} else {
|
||||
groups.append(group);
|
||||
}
|
||||
|
||||
QStringList idNames;
|
||||
for (const auto &group : groups) {
|
||||
const auto events = m_events[group];
|
||||
int indexOffset = Event::getIndexOffset(group);
|
||||
for (int i = 0; i < events.length(); i++) {
|
||||
QString idName = events.at(i)->getIdName();
|
||||
if (idName.isEmpty()) {
|
||||
idName = QString::number(i + indexOffset);
|
||||
}
|
||||
idNames.append(idName);
|
||||
}
|
||||
}
|
||||
return idNames;
|
||||
}
|
||||
|
||||
int Map::getNumEvents(Event::Group group) const {
|
||||
if (group == Event::Group::None) {
|
||||
// Total number of events
|
||||
|
|
|
|||
129
src/editor.cpp
129
src/editor.cpp
|
|
@ -1,5 +1,5 @@
|
|||
#include "editor.h"
|
||||
#include "draggablepixmapitem.h"
|
||||
#include "eventpixmapitem.h"
|
||||
#include "imageproviders.h"
|
||||
#include "log.h"
|
||||
#include "connectionslistitem.h"
|
||||
|
|
@ -1345,7 +1345,6 @@ void Editor::setStraightPathCursorMode(QGraphicsSceneMouseEvent *event) {
|
|||
}
|
||||
|
||||
void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item) {
|
||||
// TODO: add event tab event painting tool buttons stuff here
|
||||
if (!item->getEditsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1419,8 +1418,11 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *i
|
|||
if (event && event->getPixmapItem())
|
||||
event->getPixmapItem()->moveTo(pos);
|
||||
}
|
||||
} else if (eventEditAction == EditAction::Select) {
|
||||
// do nothing here, at least for now
|
||||
} else if (eventEditAction == EditAction::Select && event->type() == QEvent::GraphicsSceneMousePress) {
|
||||
if (!(event->modifiers() & Qt::ControlModifier) && this->selectedEvents.length() > 1) {
|
||||
// User is clearing group selection by clicking on the background
|
||||
selectMapEvent(this->selectedEvents.first());
|
||||
}
|
||||
} else if (eventEditAction == EditAction::Shift) {
|
||||
static QPoint selection_origin;
|
||||
|
||||
|
|
@ -1538,7 +1540,7 @@ bool Editor::displayLayout() {
|
|||
scene->installEventFilter(filter);
|
||||
connect(filter, &MapSceneEventFilter::wheelZoom, this, &Editor::onWheelZoom);
|
||||
scene->installEventFilter(this->map_ruler);
|
||||
this->map_ruler->setZValue(1000);
|
||||
this->map_ruler->setZValue(ZValue::Ruler);
|
||||
scene->addItem(this->map_ruler);
|
||||
}
|
||||
|
||||
|
|
@ -1723,9 +1725,6 @@ void Editor::clearMapEvents() {
|
|||
if (events_group->scene()) {
|
||||
events_group->scene()->removeItem(events_group);
|
||||
}
|
||||
// events_group does not own its children, the childrens' parent
|
||||
// is set to the group's parent (and our group has no parent).
|
||||
qDeleteAll(events_group->childItems());
|
||||
delete events_group;
|
||||
events_group = nullptr;
|
||||
}
|
||||
|
|
@ -1745,9 +1744,15 @@ void Editor::displayMapEvents() {
|
|||
events_group->setHandlesChildEvents(false);
|
||||
}
|
||||
|
||||
DraggablePixmapItem *Editor::addEventPixmapItem(Event *event) {
|
||||
EventPixmapItem *Editor::addEventPixmapItem(Event *event) {
|
||||
this->project->loadEventPixmap(event);
|
||||
auto item = new DraggablePixmapItem(event, this);
|
||||
auto item = new EventPixmapItem(event);
|
||||
connect(item, &EventPixmapItem::doubleClicked, this, &Editor::openEventMap);
|
||||
connect(item, &EventPixmapItem::dragged, this, &Editor::onEventDragged);
|
||||
connect(item, &EventPixmapItem::released, this, &Editor::onEventReleased);
|
||||
connect(item, &EventPixmapItem::selected, this, &Editor::selectMapEvent);
|
||||
connect(item, &EventPixmapItem::posChanged, [this, event] { updateWarpEventWarning(event); });
|
||||
connect(item, &EventPixmapItem::yChanged, [this, item] { updateEventPixmapItemZValue(item); });
|
||||
redrawEventPixmapItem(item);
|
||||
this->events_group->addToGroup(item);
|
||||
return item;
|
||||
|
|
@ -1821,6 +1826,7 @@ void Editor::maskNonVisibleConnectionTiles() {
|
|||
QBrush brush(ui->graphicsView_Map->palette().color(QPalette::Active, QPalette::Base));
|
||||
|
||||
connection_mask = scene->addPath(mask, pen, brush);
|
||||
connection_mask->setZValue(ZValue::MapConnectionMask);
|
||||
}
|
||||
|
||||
void Editor::clearMapBorder() {
|
||||
|
|
@ -1843,7 +1849,7 @@ void Editor::displayMapBorder() {
|
|||
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
|
||||
item->setX(x * 16);
|
||||
item->setY(y * 16);
|
||||
item->setZValue(-3);
|
||||
item->setZValue(ZValue::MapBorder);
|
||||
scene->addItem(item);
|
||||
borderItems.append(item);
|
||||
}
|
||||
|
|
@ -2013,32 +2019,59 @@ qreal Editor::getEventOpacity(const Event *event) const {
|
|||
return event->getUsesDefaultPixmap() ? 0.7 : 1.0;
|
||||
}
|
||||
|
||||
void Editor::redrawEventPixmapItem(DraggablePixmapItem *item) {
|
||||
if (item && item->event && !item->event->getPixmap().isNull()) {
|
||||
item->setOpacity(getEventOpacity(item->event));
|
||||
project->loadEventPixmap(item->event, true);
|
||||
item->setPixmap(item->event->getPixmap());
|
||||
item->setShapeMode(porymapConfig.eventSelectionShapeMode);
|
||||
void Editor::redrawEventPixmapItem(EventPixmapItem *item) {
|
||||
if (!item) return;
|
||||
Event *event = item->getEvent();
|
||||
if (!event) return;
|
||||
|
||||
if (this->editMode == EditMode::Events) {
|
||||
if (this->selectedEvents.contains(item->event)) {
|
||||
// Draw the selection rectangle
|
||||
QImage image = item->pixmap().toImage();
|
||||
QPainter painter(&image);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, image.width() - 1, image.height() - 1);
|
||||
painter.end();
|
||||
item->setPixmap(QPixmap::fromImage(image));
|
||||
}
|
||||
item->setAcceptedMouseButtons(Qt::AllButtons);
|
||||
} else {
|
||||
// Can't interact with event pixmaps outside of event editing mode.
|
||||
// We could do setEnabled(false), but rather than ignoring the mouse events this
|
||||
// would reject them, which would prevent painting on the map behind the events.
|
||||
item->setAcceptedMouseButtons(Qt::NoButton);
|
||||
}
|
||||
item->updatePosition();
|
||||
if (this->editMode == EditMode::Events) {
|
||||
item->setAcceptedMouseButtons(Qt::AllButtons);
|
||||
item->setSelected(this->selectedEvents.contains(event));
|
||||
} else {
|
||||
// Can't interact with event pixmaps outside of event editing mode.
|
||||
// We could do setEnabled(false), but rather than ignoring the mouse events this
|
||||
// would reject them, which would prevent painting on the map behind the events.
|
||||
item->setAcceptedMouseButtons(Qt::NoButton);
|
||||
item->setSelected(false);
|
||||
}
|
||||
updateEventPixmapItemZValue(item);
|
||||
item->setOpacity(getEventOpacity(event));
|
||||
item->setShapeMode(porymapConfig.eventSelectionShapeMode);
|
||||
item->render(project);
|
||||
}
|
||||
|
||||
void Editor::updateEventPixmapItemZValue(EventPixmapItem *item) {
|
||||
if (!item) return;
|
||||
Event *event = item->getEvent();
|
||||
if (!event) return;
|
||||
|
||||
if (item->isSelected()) {
|
||||
item->setZValue(ZValue::EventMaximum);
|
||||
} else {
|
||||
item->setZValue(event->getY() + ((ZValue::EventMaximum - ZValue::EventMinimum) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onEventDragged(Event *event, const QPoint &oldPosition, const QPoint &newPosition) {
|
||||
if (!this->map || !this->map_item)
|
||||
return;
|
||||
|
||||
this->map_item->hoveredMapMetatileChanged(newPosition);
|
||||
|
||||
// Drag all the other selected events (if any) with it
|
||||
QList<Event*> draggedEvents;
|
||||
if (this->selectedEvents.contains(event)) {
|
||||
draggedEvents = this->selectedEvents;
|
||||
} else {
|
||||
draggedEvents.append(event);
|
||||
}
|
||||
|
||||
QPoint moveDistance = newPosition - oldPosition;
|
||||
this->map->commit(new EventMove(draggedEvents, moveDistance.x(), moveDistance.y(), this->eventMoveActionId));
|
||||
}
|
||||
|
||||
void Editor::onEventReleased(Event *, const QPoint &) {
|
||||
this->eventMoveActionId++;
|
||||
}
|
||||
|
||||
// Warp events display a warning if they're not positioned on a metatile with a warp behavior.
|
||||
|
|
@ -2323,32 +2356,6 @@ bool Editor::startDetachedProcess(const QString &command, const QString &working
|
|||
return process.startDetached(pid);
|
||||
}
|
||||
|
||||
// It doesn't seem to be possible to prevent the mousePress event
|
||||
// from triggering both event's DraggablePixmapItem and the background mousePress.
|
||||
// Since the DraggablePixmapItem's event fires first, we can set a temp
|
||||
// variable "selectingEvent" so that we can detect whether or not the user
|
||||
// is clicking on the background instead of an event.
|
||||
void Editor::eventsView_onMousePress(QMouseEvent *event) {
|
||||
// make sure we are in event editing mode
|
||||
if (map_item && this->editMode != EditMode::Events) {
|
||||
return;
|
||||
}
|
||||
if (this->eventEditAction == EditAction::Paint && event->buttons() & Qt::RightButton) {
|
||||
this->eventEditAction = EditAction::Select;
|
||||
this->settings->mapCursor = QCursor();
|
||||
this->cursorMapTileRect->setSingleTileMode();
|
||||
this->ui->toolButton_Paint->setChecked(false);
|
||||
this->ui->toolButton_Select->setChecked(true);
|
||||
}
|
||||
|
||||
bool multiSelect = event->modifiers() & Qt::ControlModifier;
|
||||
if (!selectingEvent && !multiSelect && this->selectedEvents.length() > 1) {
|
||||
// User is clearing group selection by clicking on the background
|
||||
this->selectMapEvent(this->selectedEvents.first());
|
||||
}
|
||||
selectingEvent = false;
|
||||
}
|
||||
|
||||
void Editor::setCollisionTabSpinBoxes(uint16_t collision, uint16_t elevation) {
|
||||
const QSignalBlocker blocker1(ui->spinBox_SelectedCollision);
|
||||
const QSignalBlocker blocker2(ui->spinBox_SelectedElevation);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "customattributesframe.h"
|
||||
#include "scripting.h"
|
||||
#include "adjustingstackedwidget.h"
|
||||
#include "draggablepixmapitem.h"
|
||||
#include "eventpixmapitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "flowlayout.h"
|
||||
#include "shortcut.h"
|
||||
|
|
@ -345,9 +345,9 @@ void MainWindow::initEditor() {
|
|||
this->editor = new Editor(ui);
|
||||
connect(this->editor, &Editor::eventsChanged, this, &MainWindow::updateEvents);
|
||||
connect(this->editor, &Editor::openConnectedMap, this, &MainWindow::onOpenConnectedMap);
|
||||
connect(this->editor, &Editor::warpEventDoubleClicked, this, &MainWindow::openWarpMap);
|
||||
connect(this->editor, &Editor::openEventMap, this, &MainWindow::openEventMap);
|
||||
connect(this->editor, &Editor::currentMetatilesSelectionChanged, this, &MainWindow::currentMetatilesSelectionChanged);
|
||||
connect(this->editor, &Editor::wildMonTableEdited, this, &MainWindow::markMapEdited);
|
||||
connect(this->editor, &Editor::wildMonTableEdited, [this] { markMapEdited(this->editor->map); });
|
||||
connect(this->editor, &Editor::mapRulerStatusChanged, this, &MainWindow::onMapRulerStatusChanged);
|
||||
connect(this->editor, &Editor::tilesetUpdated, this, &Scripting::cb_TilesetUpdated);
|
||||
connect(ui->newEventToolButton, &NewEventToolButton::newEventAdded, this->editor, &Editor::addNewEvent);
|
||||
|
|
@ -528,11 +528,7 @@ void MainWindow::updateWindowTitle() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::markMapEdited() {
|
||||
if (editor) markSpecificMapEdited(editor->map);
|
||||
}
|
||||
|
||||
void MainWindow::markSpecificMapEdited(Map* map) {
|
||||
void MainWindow::markMapEdited(Map* map) {
|
||||
if (!map)
|
||||
return;
|
||||
map->setHasUnsavedDataChanges(true);
|
||||
|
|
@ -956,8 +952,6 @@ bool MainWindow::setMap(QString map_name) {
|
|||
updateMapList();
|
||||
resetMapListFilters();
|
||||
|
||||
connect(editor->map, &Map::modified, this, &MainWindow::markMapEdited, Qt::UniqueConnection);
|
||||
|
||||
// If the map's MAPSEC / layout changes, update the map's position in the map list.
|
||||
// These are doing more work than necessary, rather than rebuilding the entire list they should find and relocate the appropriate row.
|
||||
connect(editor->map, &Map::layoutChanged, this, &MainWindow::rebuildMapList_Layouts, Qt::UniqueConnection);
|
||||
|
|
@ -1070,20 +1064,57 @@ void MainWindow::refreshCollisionSelector() {
|
|||
on_horizontalSlider_CollisionZoom_valueChanged(ui->horizontalSlider_CollisionZoom->value());
|
||||
}
|
||||
|
||||
void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) {
|
||||
// Open the destination map.
|
||||
if (!userSetMap(map_name))
|
||||
// Some events (like warps) have data that refers to an event on a different map.
|
||||
// This function opens that map, and selects the event it's referring to.
|
||||
void MainWindow::openEventMap(Event *sourceEvent) {
|
||||
if (!sourceEvent || !this->editor->map) return;
|
||||
|
||||
QString targetMapName;
|
||||
QString targetEventIdName;
|
||||
Event::Group targetEventGroup;
|
||||
|
||||
Event::Type eventType = sourceEvent->getEventType();
|
||||
if (eventType == Event::Type::Warp) {
|
||||
// Warp events open to their destination warp event.
|
||||
WarpEvent *warp = dynamic_cast<WarpEvent *>(sourceEvent);
|
||||
targetMapName = warp->getDestinationMap();
|
||||
targetEventIdName = warp->getDestinationWarpID();
|
||||
targetEventGroup = Event::Group::Warp;
|
||||
} else if (eventType == Event::Type::CloneObject) {
|
||||
// Clone object events open to their target object event.
|
||||
CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(sourceEvent);
|
||||
targetMapName = clone->getTargetMap();
|
||||
targetEventIdName = clone->getTargetID();
|
||||
targetEventGroup = Event::Group::Object;
|
||||
} else if (eventType == Event::Type::SecretBase) {
|
||||
// Secret Bases open to their secret base entrance
|
||||
const QString mapPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix);
|
||||
SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(sourceEvent);
|
||||
|
||||
// Extract the map name from the secret base ID.
|
||||
QString baseId = base->getBaseID();
|
||||
targetMapName = this->editor->project->mapConstantsToMapNames.value(mapPrefix + baseId.left(baseId.lastIndexOf("_")));
|
||||
|
||||
// Just select the first warp. Normally the only warp event on every secret base map is the entrance/exit, so this is usually correct.
|
||||
// The warp IDs for secret bases are specified in the project's C code, not in the map data, so we don't have an easy way to read the actual IDs.
|
||||
targetEventIdName = "0";
|
||||
targetEventGroup = Event::Group::Warp;
|
||||
} else if (eventType == Event::Type::HealLocation && projectConfig.healLocationRespawnDataEnabled) {
|
||||
// Heal location events open to their respawn NPC
|
||||
HealLocationEvent *heal = dynamic_cast<HealLocationEvent *>(sourceEvent);
|
||||
targetMapName = heal->getRespawnMapName();
|
||||
targetEventIdName = heal->getRespawnNPC();
|
||||
targetEventGroup = Event::Group::Object;
|
||||
} else {
|
||||
// Other event types have no target map to open.
|
||||
return;
|
||||
}
|
||||
if (!userSetMap(targetMapName))
|
||||
return;
|
||||
|
||||
// Select the target event.
|
||||
int index = event_id - Event::getIndexOffset(event_group);
|
||||
Event* event = this->editor->map->getEvent(event_group, index);
|
||||
if (event) {
|
||||
this->editor->selectMapEvent(event);
|
||||
} else {
|
||||
// Can still warp to this map, but can't select the specified event
|
||||
logWarn(QString("%1 %2 doesn't exist on map '%3'").arg(Event::groupToString(event_group)).arg(event_id).arg(map_name));
|
||||
}
|
||||
// Map opened successfully, now try to select the targeted event on that map.
|
||||
Event *targetEvent = this->editor->map->getEvent(targetEventGroup, targetEventIdName);
|
||||
this->editor->selectMapEvent(targetEvent);
|
||||
}
|
||||
|
||||
void MainWindow::displayMapProperties() {
|
||||
|
|
@ -1123,7 +1154,7 @@ void MainWindow::on_comboBox_LayoutSelector_currentTextChanged(const QString &te
|
|||
}
|
||||
this->editor->map->setLayout(layout);
|
||||
setMap(this->editor->map->name());
|
||||
markMapEdited();
|
||||
markMapEdited(this->editor->map);
|
||||
}
|
||||
|
||||
void MainWindow::onLayoutSelectorEditingFinished() {
|
||||
|
|
@ -2488,7 +2519,7 @@ void MainWindow::onOpenConnectedMap(MapConnection *connection) {
|
|||
}
|
||||
|
||||
void MainWindow::onMapLoaded(Map *map) {
|
||||
connect(map, &Map::modified, [this, map] { this->markSpecificMapEdited(map); });
|
||||
connect(map, &Map::modified, [this, map] { markMapEdited(map); });
|
||||
}
|
||||
|
||||
void MainWindow::onTilesetsSaved(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
|
||||
|
|
|
|||
|
|
@ -159,6 +159,11 @@ void Project::clearTilesetCache() {
|
|||
}
|
||||
|
||||
Map* Project::loadMap(const QString &mapName) {
|
||||
if (mapName == getDynamicMapName()) {
|
||||
// Silently ignored, caller is expected to handle this if they want this to be an error.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Map* map = this->maps.value(mapName);
|
||||
if (!map) {
|
||||
logError(QString("Unknown map name '%1'.").arg(mapName));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "connectionpixmapitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "map.h"
|
||||
#include "editor.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ void ConnectionPixmapItem::render(bool ignoreCache) {
|
|||
this->basePixmap = this->connection->render();
|
||||
|
||||
QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||
this->setZValue(-1);
|
||||
this->setZValue(Editor::ZValue::MapConnectionActive);
|
||||
|
||||
// When editing is inactive the current selection is ignored, all connections should appear normal.
|
||||
if (this->getEditable()) {
|
||||
|
|
@ -42,7 +43,7 @@ void ConnectionPixmapItem::render(bool ignoreCache) {
|
|||
painter.end();
|
||||
} else {
|
||||
// Darken the image
|
||||
this->setZValue(-2);
|
||||
this->setZValue(Editor::ZValue::MapConnectionInactive);
|
||||
QPainter painter(&pixmap);
|
||||
int alpha = static_cast<int>(255 * 0.25);
|
||||
painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QColor(0, 0, 0, alpha));
|
||||
|
|
|
|||
|
|
@ -1,134 +0,0 @@
|
|||
#include "draggablepixmapitem.h"
|
||||
#include "editor.h"
|
||||
#include "editcommands.h"
|
||||
#include "mapruler.h"
|
||||
#include "metatile.h"
|
||||
|
||||
static unsigned currentActionId = 0;
|
||||
|
||||
|
||||
void DraggablePixmapItem::updatePosition() {
|
||||
int x = this->event->getPixelX();
|
||||
int y = this->event->getPixelY();
|
||||
setX(x);
|
||||
setY(y);
|
||||
if (this->editor->selectedEvents.contains(this->event)) {
|
||||
setZValue(event->getY() + 1);
|
||||
} else {
|
||||
setZValue(event->getY());
|
||||
}
|
||||
editor->updateWarpEventWarning(event);
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::emitPositionChanged() {
|
||||
emit xChanged(event->getX());
|
||||
emit yChanged(event->getY());
|
||||
emit elevationChanged(event->getElevation());
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::updatePixmap() {
|
||||
editor->project->loadEventPixmap(event, true);
|
||||
this->updatePosition();
|
||||
editor->redrawEventPixmapItem(this);
|
||||
emit spriteChanged(event->getPixmap());
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
if (this->active)
|
||||
return;
|
||||
this->active = true;
|
||||
this->lastPos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
|
||||
bool selectionToggle = mouse->modifiers() & Qt::ControlModifier;
|
||||
if (selectionToggle || !this->editor->selectedEvents.contains(this->event)) {
|
||||
// User is either toggling this selection on/off as part of a group selection,
|
||||
// or they're newly selecting just this item.
|
||||
this->editor->selectMapEvent(this->event, selectionToggle);
|
||||
} else {
|
||||
// This item is already selected and the user isn't toggling the selection, so there are 4 possibilities:
|
||||
// 1. This is the only selected event, and the selection is pointless.
|
||||
// 2. This is the only selected event, and they want to drag the item around.
|
||||
// 3. There's a group selection, and they want to start a new selection with just this item.
|
||||
// 4. There's a group selection, and they want to drag the group around.
|
||||
// 'selectMapEvent' will immediately clear the rest of the selection, which supports #1-3 but prevents #4.
|
||||
// To support #4 we set the flag below, and we only call 'selectMapEvent' on mouse release if no move occurred.
|
||||
this->releaseSelectionQueued = true;
|
||||
}
|
||||
this->editor->selectingEvent = true;
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::move(int dx, int dy) {
|
||||
event->setX(event->getX() + dx);
|
||||
event->setY(event->getY() + dy);
|
||||
updatePosition();
|
||||
emitPositionChanged();
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::moveTo(const QPoint &pos) {
|
||||
event->setX(pos.x());
|
||||
event->setY(pos.y());
|
||||
updatePosition();
|
||||
emitPositionChanged();
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
if (!this->active)
|
||||
return;
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
if (pos == this->lastPos)
|
||||
return;
|
||||
|
||||
QPoint moveDistance = pos - this->lastPos;
|
||||
this->lastPos = pos;
|
||||
emit this->editor->map_item->hoveredMapMetatileChanged(pos);
|
||||
|
||||
QList <Event *> selectedEvents;
|
||||
if (this->editor->selectedEvents.contains(this->event)) {
|
||||
selectedEvents = this->editor->selectedEvents;
|
||||
} else {
|
||||
selectedEvents.append(this->event);
|
||||
}
|
||||
editor->map->commit(new EventMove(selectedEvents, moveDistance.x(), moveDistance.y(), currentActionId));
|
||||
this->releaseSelectionQueued = false;
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
if (!this->active)
|
||||
return;
|
||||
this->active = false;
|
||||
currentActionId++;
|
||||
if (this->releaseSelectionQueued) {
|
||||
this->releaseSelectionQueued = false;
|
||||
if (Metatile::coordFromPixmapCoord(mouse->scenePos()) == this->lastPos)
|
||||
this->editor->selectMapEvent(this->event);
|
||||
}
|
||||
}
|
||||
|
||||
// Events with properties that specify a map will open that map when double-clicked.
|
||||
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
Event::Type eventType = this->event->getEventType();
|
||||
if (eventType == Event::Type::Warp) {
|
||||
WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event);
|
||||
QString destMap = warp->getDestinationMap();
|
||||
int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID());
|
||||
emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp);
|
||||
}
|
||||
else if (eventType == Event::Type::CloneObject) {
|
||||
CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event);
|
||||
emit editor->warpEventDoubleClicked(clone->getTargetMap(), clone->getTargetID(), Event::Group::Object);
|
||||
}
|
||||
else if (eventType == Event::Type::SecretBase) {
|
||||
const QString mapPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix);
|
||||
SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event);
|
||||
QString baseId = base->getBaseID();
|
||||
QString destMap = editor->project->mapConstantsToMapNames.value(mapPrefix + baseId.left(baseId.lastIndexOf("_")));
|
||||
emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp);
|
||||
}
|
||||
else if (eventType == Event::Type::HealLocation && projectConfig.healLocationRespawnDataEnabled) {
|
||||
HealLocationEvent *heal = dynamic_cast<HealLocationEvent *>(this->event);
|
||||
const QString localIdName = heal->getRespawnNPC();
|
||||
int localId = 0; // TODO: Get value from localIdName
|
||||
emit editor->warpEventDoubleClicked(heal->getRespawnMapName(), localId, Event::Group::Object);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "eventframes.h"
|
||||
#include "customattributesframe.h"
|
||||
#include "editcommands.h"
|
||||
#include "draggablepixmapitem.h"
|
||||
#include "eventpixmapitem.h"
|
||||
|
||||
#include <limits>
|
||||
using std::numeric_limits;
|
||||
|
|
@ -74,6 +74,7 @@ void EventFrame::setup() {
|
|||
this->label_id = new QLabel("event_type");
|
||||
l_vbox_1->addWidget(this->label_id);
|
||||
l_vbox_1->addLayout(l_layout_xyz);
|
||||
this->label_id->setText(Event::typeToString(this->event->getEventType()));
|
||||
|
||||
// icon / pixmap label
|
||||
this->label_icon = new QLabel(this);
|
||||
|
|
@ -113,7 +114,7 @@ void EventFrame::connectSignals(MainWindow *) {
|
|||
}
|
||||
});
|
||||
|
||||
connect(this->event->getPixmapItem(), &DraggablePixmapItem::xChanged, this->spinner_x, &NoScrollSpinBox::setValue);
|
||||
connect(this->event->getPixmapItem(), &EventPixmapItem::xChanged, this->spinner_x, &NoScrollSpinBox::setValue);
|
||||
|
||||
this->spinner_y->disconnect();
|
||||
connect(this->spinner_y, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
|
||||
|
|
@ -122,7 +123,7 @@ void EventFrame::connectSignals(MainWindow *) {
|
|||
this->event->getMap()->commit(new EventMove(QList<Event *>() << this->event, 0, delta, this->spinner_y->getActionId()));
|
||||
}
|
||||
});
|
||||
connect(this->event->getPixmapItem(), &DraggablePixmapItem::yChanged, this->spinner_y, &NoScrollSpinBox::setValue);
|
||||
connect(this->event->getPixmapItem(), &EventPixmapItem::yChanged, this->spinner_y, &NoScrollSpinBox::setValue);
|
||||
|
||||
this->spinner_z->disconnect();
|
||||
connect(this->spinner_z, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
|
||||
|
|
@ -172,19 +173,31 @@ void EventFrame::setActive(bool active) {
|
|||
this->blockSignals(!active);
|
||||
}
|
||||
|
||||
void EventFrame::populateDropdown(NoScrollComboBox * combo, const QStringList &items) {
|
||||
// Set the items in the combo box. This may be called after the frame is initialized
|
||||
// if the frame needs to be repopulated, so ensure the text in the combo is preserved
|
||||
// and that we don't accidentally fire 'currentTextChanged'.
|
||||
const QSignalBlocker b(combo);
|
||||
const QString savedText = combo->currentText();
|
||||
combo->clear();
|
||||
combo->addItems(items);
|
||||
combo->setCurrentText(savedText);
|
||||
}
|
||||
|
||||
void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * project) {
|
||||
// The script dropdown and autocomplete are populated with scripts used by the map's events and from its scripts file.
|
||||
if (!this->event->getMap())
|
||||
return;
|
||||
|
||||
QStringList scripts = this->event->getMap()->getScriptLabels(this->event->getEventGroup());
|
||||
combo->addItems(scripts);
|
||||
populateDropdown(combo, scripts);
|
||||
|
||||
// Depending on the settings, the autocomplete may also contain all global scripts.
|
||||
if (porymapConfig.loadAllEventScripts) {
|
||||
project->insertGlobalScriptLabels(scripts);
|
||||
}
|
||||
|
||||
// Note: Because 'combo' is the parent, the old QCompleter will be deleted when a new one is set.
|
||||
auto completer = new QCompleter(scripts, combo);
|
||||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||
completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
|
||||
|
|
@ -197,14 +210,32 @@ void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * proj
|
|||
combo->setCompleter(completer);
|
||||
|
||||
// If the project changes the script labels, update the EventFrame.
|
||||
// TODO: At the moment this only happens when the user changes script settings (i.e. when 'porymapConfig.loadAllEventScripts' changes).
|
||||
// This should ultimately be connected to a file watcher so that we can also update the dropdown when the scripts file changes.
|
||||
connect(project, &Project::eventScriptLabelsRead, this, &EventFrame::invalidateValues, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void EventFrame::populateIdNameDropdown(NoScrollComboBox * combo, Project * project, const QString &mapName, Event::Group group) {
|
||||
if (!project->mapNames.contains(mapName))
|
||||
return;
|
||||
|
||||
Map *map = project->loadMap(mapName);
|
||||
if (map) populateDropdown(combo, map->getEventIdNames(group));
|
||||
}
|
||||
|
||||
|
||||
void ObjectFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Object");
|
||||
// local id
|
||||
QFormLayout *l_form_local_id = new QFormLayout();
|
||||
this->line_edit_local_id = new QLineEdit(this);
|
||||
static const QString line_edit_local_id_toolTip = Util::toHtmlParagraph("An optional, unique name to use to refer to this object in scripts. "
|
||||
"If no name is given you can refer to this object using its 'object id' number.");
|
||||
this->line_edit_local_id->setToolTip(line_edit_local_id_toolTip);
|
||||
this->line_edit_local_id->setPlaceholderText("LOCALID_MY_NPC");
|
||||
l_form_local_id->addRow("Local ID", this->line_edit_local_id);
|
||||
this->layout_contents->addLayout(l_form_local_id);
|
||||
|
||||
// sprite combo
|
||||
QFormLayout *l_form_sprite = new QFormLayout();
|
||||
|
|
@ -294,21 +325,29 @@ void ObjectFrame::connectSignals(MainWindow *window) {
|
|||
if (this->connected) return;
|
||||
|
||||
EventFrame::connectSignals(window);
|
||||
Project *project = window->editor->project;
|
||||
|
||||
// local id
|
||||
this->line_edit_local_id->disconnect();
|
||||
connect(this->line_edit_local_id, &QLineEdit::textChanged, [this](const QString &text) {
|
||||
this->object->setIdName(text);
|
||||
this->object->modify();
|
||||
});
|
||||
|
||||
// sprite update
|
||||
this->combo_sprite->disconnect();
|
||||
connect(this->combo_sprite, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
connect(this->combo_sprite, &QComboBox::currentTextChanged, [this, project](const QString &text) {
|
||||
this->object->setGfx(text);
|
||||
this->object->getPixmapItem()->updatePixmap();
|
||||
this->object->getPixmapItem()->render(project);
|
||||
this->object->modify();
|
||||
});
|
||||
connect(this->object->getPixmapItem(), &DraggablePixmapItem::spriteChanged, this->label_icon, &QLabel::setPixmap);
|
||||
connect(this->object->getPixmapItem(), &EventPixmapItem::rendered, this->label_icon, &QLabel::setPixmap);
|
||||
|
||||
// movement
|
||||
this->combo_movement->disconnect();
|
||||
connect(this->combo_movement, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
connect(this->combo_movement, &QComboBox::currentTextChanged, [this, project](const QString &text) {
|
||||
this->object->setMovement(text);
|
||||
this->object->getPixmapItem()->updatePixmap();
|
||||
this->object->getPixmapItem()->render(project);
|
||||
this->object->modify();
|
||||
});
|
||||
|
||||
|
|
@ -366,6 +405,9 @@ void ObjectFrame::initialize() {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::initialize();
|
||||
|
||||
// local id
|
||||
this->line_edit_local_id->setText(this->object->getIdName());
|
||||
|
||||
// sprite
|
||||
this->combo_sprite->setTextItem(this->object->getGfx());
|
||||
|
||||
|
|
@ -397,12 +439,11 @@ void ObjectFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_sprite->addItems(project->gfxDefines.keys());
|
||||
this->combo_movement->addItems(project->movementTypes);
|
||||
this->combo_flag->addItems(project->flagNames);
|
||||
this->combo_trainer_type->addItems(project->trainerTypes);
|
||||
|
||||
this->populateScriptDropdown(this->combo_script, project);
|
||||
populateDropdown(this->combo_sprite, project->gfxDefines.keys());
|
||||
populateDropdown(this->combo_movement, project->movementTypes);
|
||||
populateDropdown(this->combo_flag, project->flagNames);
|
||||
populateDropdown(this->combo_trainer_type, project->trainerTypes);
|
||||
populateScriptDropdown(this->combo_script, project);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -410,13 +451,25 @@ void ObjectFrame::populate(Project *project) {
|
|||
void CloneObjectFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Clone Object");
|
||||
|
||||
this->spinner_z->setEnabled(false);
|
||||
|
||||
// local id
|
||||
QFormLayout *l_form_local_id = new QFormLayout();
|
||||
this->line_edit_local_id = new QLineEdit(this);
|
||||
static const QString line_edit_local_id_toolTip = Util::toHtmlParagraph("An optional, unique name to use to refer to this object in scripts. "
|
||||
"If no name is given you can refer to this object using its 'object id' number.");
|
||||
this->line_edit_local_id->setToolTip(line_edit_local_id_toolTip);
|
||||
this->line_edit_local_id->setPlaceholderText("LOCALID_MY_CLONE_NPC");
|
||||
l_form_local_id->addRow("Local ID", this->line_edit_local_id);
|
||||
this->layout_contents->addLayout(l_form_local_id);
|
||||
|
||||
// sprite combo (edits disabled)
|
||||
QFormLayout *l_form_sprite = new QFormLayout();
|
||||
this->combo_sprite = new NoScrollComboBox(this);
|
||||
static const QString combo_sprite_toolTip = Util::toHtmlParagraph("The sprite graphics to use for this object. This is updated automatically "
|
||||
"to match the target object, and so can't be edited. By default the games "
|
||||
"will get the graphics directly from the target object, so this field is ignored.");
|
||||
this->combo_sprite->setToolTip(combo_sprite_toolTip);
|
||||
l_form_sprite->addRow("Sprite", this->combo_sprite);
|
||||
this->combo_sprite->setEnabled(false);
|
||||
this->layout_contents->addLayout(l_form_sprite);
|
||||
|
|
@ -429,12 +482,12 @@ void CloneObjectFrame::setup() {
|
|||
l_form_dest_map->addRow("Target Map", this->combo_target_map);
|
||||
this->layout_contents->addLayout(l_form_dest_map);
|
||||
|
||||
// clone local id spinbox
|
||||
// clone local id combo
|
||||
QFormLayout *l_form_dest_id = new QFormLayout();
|
||||
this->spinner_target_id = new NoScrollSpinBox(this);
|
||||
static const QString spinner_target_id_toolTip = Util::toHtmlParagraph("event_object ID of the object being cloned.");
|
||||
this->spinner_target_id->setToolTip(spinner_target_id_toolTip);
|
||||
l_form_dest_id->addRow("Target Local ID", this->spinner_target_id);
|
||||
this->combo_target_id = new NoScrollComboBox(this);
|
||||
static const QString combo_target_id_toolTip = Util::toHtmlParagraph("The Local ID name or number of the object being cloned.");
|
||||
this->combo_target_id->setToolTip(combo_target_id_toolTip);
|
||||
l_form_dest_id->addRow("Target Local ID", this->combo_target_id);
|
||||
this->layout_contents->addLayout(l_form_dest_id);
|
||||
|
||||
// custom attributes
|
||||
|
|
@ -445,27 +498,48 @@ void CloneObjectFrame::connectSignals(MainWindow *window) {
|
|||
if (this->connected) return;
|
||||
|
||||
EventFrame::connectSignals(window);
|
||||
Project *project = window->editor->project;
|
||||
|
||||
// local id
|
||||
this->line_edit_local_id->disconnect();
|
||||
connect(this->line_edit_local_id, &QLineEdit::textChanged, [this](const QString &text) {
|
||||
this->clone->setIdName(text);
|
||||
this->clone->modify();
|
||||
});
|
||||
|
||||
// update icon displayed in frame with target
|
||||
connect(this->clone->getPixmapItem(), &DraggablePixmapItem::spriteChanged, this->label_icon, &QLabel::setPixmap);
|
||||
connect(this->clone->getPixmapItem(), &EventPixmapItem::rendered, this->label_icon, &QLabel::setPixmap);
|
||||
|
||||
// target map
|
||||
this->combo_target_map->disconnect();
|
||||
connect(this->combo_target_map, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->clone->setTargetMap(text);
|
||||
this->clone->getPixmapItem()->updatePixmap();
|
||||
connect(this->combo_target_map, &QComboBox::currentTextChanged, [this, project](const QString &mapName) {
|
||||
this->clone->setTargetMap(mapName);
|
||||
this->clone->getPixmapItem()->render(project);
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->clone->modify();
|
||||
populateIdNameDropdown(this->combo_target_id, project, mapName, Event::Group::Object);
|
||||
});
|
||||
connect(window, &MainWindow::mapOpened, this, &CloneObjectFrame::tryInvalidateIdDropdown, Qt::UniqueConnection);
|
||||
|
||||
// target id
|
||||
this->combo_target_id->disconnect();
|
||||
connect(this->combo_target_id, &QComboBox::currentTextChanged, [this, project](const QString &text) {
|
||||
this->clone->setTargetID(text);
|
||||
this->clone->getPixmapItem()->render(project);
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->clone->modify();
|
||||
});
|
||||
|
||||
// target id
|
||||
this->spinner_target_id->disconnect();
|
||||
connect(this->spinner_target_id, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
|
||||
this->clone->setTargetID(value);
|
||||
this->clone->getPixmapItem()->updatePixmap();
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
this->clone->modify();
|
||||
});
|
||||
// This frame type displays map names, so when a new map is created we need to repopulate it.
|
||||
connect(project, &Project::mapCreated, this, &EventFrame::invalidateValues, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void CloneObjectFrame::tryInvalidateIdDropdown(Map *map) {
|
||||
// If the clone's target map is opened then the names in this frame's ID dropdown may be changed.
|
||||
// Make sure we update the frame next time it's opened.
|
||||
if (map && this->clone && map->name() == this->clone->getTargetMap()) {
|
||||
invalidateValues();
|
||||
}
|
||||
}
|
||||
|
||||
void CloneObjectFrame::initialize() {
|
||||
|
|
@ -474,13 +548,14 @@ void CloneObjectFrame::initialize() {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::initialize();
|
||||
|
||||
// local id
|
||||
this->line_edit_local_id->setText(this->clone->getIdName());
|
||||
|
||||
// sprite
|
||||
this->combo_sprite->setCurrentText(this->clone->getGfx());
|
||||
|
||||
// target id
|
||||
this->spinner_target_id->setMinimum(1);
|
||||
this->spinner_target_id->setMaximum(126);
|
||||
this->spinner_target_id->setValue(this->clone->getTargetID());
|
||||
this->combo_target_id->setCurrentText(this->clone->getTargetID());
|
||||
|
||||
// target map
|
||||
this->combo_target_map->setTextItem(this->clone->getTargetMap());
|
||||
|
|
@ -492,13 +567,22 @@ void CloneObjectFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_target_map->addItems(project->mapNames);
|
||||
populateDropdown(this->combo_target_map, project->mapNames);
|
||||
populateIdNameDropdown(this->combo_target_id, project, this->clone->getTargetMap(), Event::Group::Object);
|
||||
}
|
||||
|
||||
void WarpFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Warp");
|
||||
// ID
|
||||
QFormLayout *l_form_id = new QFormLayout();
|
||||
this->line_edit_id = new QLineEdit(this);
|
||||
static const QString line_edit_id_toolTip = Util::toHtmlParagraph("An optional, unique name to use to refer to this warp from other warps. "
|
||||
"If no name is given you can refer to this warp using its 'warp id' number.");
|
||||
this->line_edit_id->setToolTip(line_edit_id_toolTip);
|
||||
this->line_edit_id->setPlaceholderText("WARP_ID_MY_WARP");
|
||||
l_form_id->addRow("ID", this->line_edit_id);
|
||||
this->layout_contents->addLayout(l_form_id);
|
||||
|
||||
// desination map combo
|
||||
QFormLayout *l_form_dest_map = new QFormLayout();
|
||||
|
|
@ -534,13 +618,23 @@ void WarpFrame::connectSignals(MainWindow *window) {
|
|||
if (this->connected) return;
|
||||
|
||||
EventFrame::connectSignals(window);
|
||||
Project *project = window->editor->project;
|
||||
|
||||
// id
|
||||
this->line_edit_id->disconnect();
|
||||
connect(this->line_edit_id, &QLineEdit::textChanged, [this](const QString &text) {
|
||||
this->warp->setIdName(text);
|
||||
this->warp->modify();
|
||||
});
|
||||
|
||||
// dest map
|
||||
this->combo_dest_map->disconnect();
|
||||
connect(this->combo_dest_map, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->warp->setDestinationMap(text);
|
||||
connect(this->combo_dest_map, &QComboBox::currentTextChanged, [this, project](const QString &mapName) {
|
||||
this->warp->setDestinationMap(mapName);
|
||||
this->warp->modify();
|
||||
populateIdNameDropdown(this->combo_dest_warp, project, mapName, Event::Group::Warp);
|
||||
});
|
||||
connect(window, &MainWindow::mapOpened, this, &WarpFrame::tryInvalidateIdDropdown, Qt::UniqueConnection);
|
||||
|
||||
// dest id
|
||||
this->combo_dest_warp->disconnect();
|
||||
|
|
@ -552,6 +646,17 @@ void WarpFrame::connectSignals(MainWindow *window) {
|
|||
// warning
|
||||
this->warning->disconnect();
|
||||
connect(this->warning, &QPushButton::clicked, window, &MainWindow::onWarpBehaviorWarningClicked);
|
||||
|
||||
// This frame type displays map names, so when a new map is created we need to repopulate it.
|
||||
connect(project, &Project::mapCreated, this, &EventFrame::invalidateValues, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void WarpFrame::tryInvalidateIdDropdown(Map *map) {
|
||||
// If the warps's target map is opened then the names in this frame's ID dropdown may be changed.
|
||||
// Make sure we update the frame next time it's opened.
|
||||
if (map && this->warp && map->name() == this->warp->getDestinationMap()) {
|
||||
invalidateValues();
|
||||
}
|
||||
}
|
||||
|
||||
void WarpFrame::initialize() {
|
||||
|
|
@ -560,6 +665,9 @@ void WarpFrame::initialize() {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::initialize();
|
||||
|
||||
// id
|
||||
this->line_edit_id->setText(this->warp->getIdName());
|
||||
|
||||
// dest map
|
||||
this->combo_dest_map->setTextItem(this->warp->getDestinationMap());
|
||||
|
||||
|
|
@ -573,7 +681,8 @@ void WarpFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_dest_map->addItems(project->mapNames);
|
||||
populateDropdown(this->combo_dest_map, project->mapNames);
|
||||
populateIdNameDropdown(this->combo_dest_warp, project, this->warp->getDestinationMap(), Event::Group::Warp);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -581,8 +690,6 @@ void WarpFrame::populate(Project *project) {
|
|||
void TriggerFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Trigger");
|
||||
|
||||
// script combo
|
||||
QFormLayout *l_form_script = new QFormLayout();
|
||||
this->combo_script = new NoScrollComboBox(this);
|
||||
|
|
@ -661,10 +768,8 @@ void TriggerFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
// var combo
|
||||
this->combo_var->addItems(project->varNames);
|
||||
|
||||
this->populateScriptDropdown(this->combo_script, project);
|
||||
populateDropdown(this->combo_var, project->varNames);
|
||||
populateScriptDropdown(this->combo_script, project);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -672,8 +777,6 @@ void TriggerFrame::populate(Project *project) {
|
|||
void WeatherTriggerFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Weather Trigger");
|
||||
|
||||
// weather combo
|
||||
QFormLayout *l_form_weather = new QFormLayout();
|
||||
this->combo_weather = new NoScrollComboBox(this);
|
||||
|
|
@ -715,8 +818,7 @@ void WeatherTriggerFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
// weather
|
||||
this->combo_weather->addItems(project->coordEventWeatherNames);
|
||||
populateDropdown(this->combo_weather, project->coordEventWeatherNames);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -724,8 +826,6 @@ void WeatherTriggerFrame::populate(Project *project) {
|
|||
void SignFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Sign");
|
||||
|
||||
// facing dir combo
|
||||
QFormLayout *l_form_facing_dir = new QFormLayout();
|
||||
this->combo_facing_dir = new NoScrollComboBox(this);
|
||||
|
|
@ -785,10 +885,8 @@ void SignFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
// facing dir
|
||||
this->combo_facing_dir->addItems(project->bgEventFacingDirections);
|
||||
|
||||
this->populateScriptDropdown(this->combo_script, project);
|
||||
populateDropdown(this->combo_facing_dir, project->bgEventFacingDirections);
|
||||
populateScriptDropdown(this->combo_script, project);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -796,8 +894,6 @@ void SignFrame::populate(Project *project) {
|
|||
void HiddenItemFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Hidden Item");
|
||||
|
||||
// item combo
|
||||
QFormLayout *l_form_item = new QFormLayout();
|
||||
this->combo_item = new NoScrollComboBox(this);
|
||||
|
|
@ -905,8 +1001,8 @@ void HiddenItemFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_item->addItems(project->itemNames);
|
||||
this->combo_flag->addItems(project->flagNames);
|
||||
populateDropdown(this->combo_item, project->itemNames);
|
||||
populateDropdown(this->combo_flag, project->flagNames);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -914,8 +1010,6 @@ void HiddenItemFrame::populate(Project *project) {
|
|||
void SecretBaseFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Secret Base");
|
||||
|
||||
this->spinner_z->setEnabled(false);
|
||||
|
||||
// item combo
|
||||
|
|
@ -959,7 +1053,7 @@ void SecretBaseFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_base_id->addItems(project->secretBaseIds);
|
||||
populateDropdown(this->combo_base_id, project->secretBaseIds);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -967,8 +1061,6 @@ void SecretBaseFrame::populate(Project *project) {
|
|||
void HealLocationFrame::setup() {
|
||||
EventFrame::setup();
|
||||
|
||||
this->label_id->setText("Heal Location");
|
||||
|
||||
this->hideable_label_z->setVisible(false);
|
||||
this->spinner_z->setVisible(false);
|
||||
|
||||
|
|
@ -996,7 +1088,8 @@ void HealLocationFrame::setup() {
|
|||
QFormLayout *l_form_respawn_npc = new QFormLayout(hideable_respawn_npc);
|
||||
l_form_respawn_npc->setContentsMargins(0, 0, 0, 0);
|
||||
this->combo_respawn_npc = new NoScrollComboBox(hideable_respawn_npc);
|
||||
static const QString combo_respawn_npc_toolTip = Util::toHtmlParagraph("event_object ID of the NPC the player interacts with upon respawning after whiteout.");
|
||||
static const QString combo_respawn_npc_toolTip = Util::toHtmlParagraph("The Local ID name or number of the NPC the player "
|
||||
"interacts with upon respawning after whiteout.");
|
||||
this->combo_respawn_npc->setToolTip(combo_respawn_npc_toolTip);
|
||||
l_form_respawn_npc->addRow("Respawn NPC", this->combo_respawn_npc);
|
||||
this->layout_contents->addWidget(hideable_respawn_npc);
|
||||
|
|
@ -1009,6 +1102,7 @@ void HealLocationFrame::connectSignals(MainWindow *window) {
|
|||
if (this->connected) return;
|
||||
|
||||
EventFrame::connectSignals(window);
|
||||
Project *project = window->editor->project;
|
||||
|
||||
this->line_edit_id->disconnect();
|
||||
connect(this->line_edit_id, &QLineEdit::textChanged, [this](const QString &text) {
|
||||
|
|
@ -1017,16 +1111,29 @@ void HealLocationFrame::connectSignals(MainWindow *window) {
|
|||
});
|
||||
|
||||
this->combo_respawn_map->disconnect();
|
||||
connect(this->combo_respawn_map, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->healLocation->setRespawnMapName(text);
|
||||
connect(this->combo_respawn_map, &QComboBox::currentTextChanged, [this, project](const QString &mapName) {
|
||||
this->healLocation->setRespawnMapName(mapName);
|
||||
this->healLocation->modify();
|
||||
populateIdNameDropdown(this->combo_respawn_npc, project, mapName, Event::Group::Object);
|
||||
});
|
||||
connect(window, &MainWindow::mapOpened, this, &HealLocationFrame::tryInvalidateIdDropdown, Qt::UniqueConnection);
|
||||
|
||||
this->combo_respawn_npc->disconnect();
|
||||
connect(this->combo_respawn_npc, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->healLocation->setRespawnNPC(text);
|
||||
this->healLocation->modify();
|
||||
});
|
||||
|
||||
// This frame type displays map names, so when a new map is created we need to repopulate it.
|
||||
connect(project, &Project::mapCreated, this, &EventFrame::invalidateValues, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void HealLocationFrame::tryInvalidateIdDropdown(Map *map) {
|
||||
// If the heal locations's target map is opened then the names in this frame's ID dropdown may be changed.
|
||||
// Make sure we update the frame next time it's opened.
|
||||
if (map && this->healLocation && map->name() == this->healLocation->getRespawnMapName()) {
|
||||
invalidateValues();
|
||||
}
|
||||
}
|
||||
|
||||
void HealLocationFrame::initialize() {
|
||||
|
|
@ -1050,7 +1157,8 @@ void HealLocationFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
this->combo_respawn_map->addItems(project->mapNames);
|
||||
// TODO: We should dynamically populate combo_respawn_npc with the local IDs of the respawn_map
|
||||
// Same for warp IDs.
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
populateDropdown(this->combo_respawn_map, project->mapNames);
|
||||
populateIdNameDropdown(this->combo_respawn_npc, project, this->healLocation->getRespawnMapName(), Event::Group::Object);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
115
src/ui/eventpixmapitem.cpp
Normal file
115
src/ui/eventpixmapitem.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include "eventpixmapitem.h"
|
||||
#include "project.h"
|
||||
#include "editcommands.h"
|
||||
#include "mapruler.h"
|
||||
#include "metatile.h"
|
||||
|
||||
EventPixmapItem::EventPixmapItem(Event *event)
|
||||
: QGraphicsPixmapItem(event->getPixmap()),
|
||||
m_basePixmap(pixmap()),
|
||||
m_event(event)
|
||||
{
|
||||
m_event->setPixmapItem(this);
|
||||
updatePixelPosition();
|
||||
}
|
||||
|
||||
void EventPixmapItem::render(Project *project) {
|
||||
if (!m_event)
|
||||
return;
|
||||
|
||||
m_basePixmap = m_event->loadPixmap(project);
|
||||
|
||||
// If the base pixmap changes, the event's pixel position may change.
|
||||
updatePixelPosition();
|
||||
|
||||
QPixmap pixmap = m_basePixmap;
|
||||
if (m_selected) {
|
||||
// Draw the selection rectangle
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(Qt::magenta);
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
}
|
||||
setPixmap(pixmap);
|
||||
emit rendered(m_basePixmap);
|
||||
}
|
||||
|
||||
void EventPixmapItem::move(int dx, int dy) {
|
||||
moveTo(m_event->getX() + dx,
|
||||
m_event->getY() + dy);
|
||||
}
|
||||
|
||||
void EventPixmapItem::moveTo(const QPoint &pos) {
|
||||
moveTo(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void EventPixmapItem::moveTo(int x, int y) {
|
||||
bool changed = false;
|
||||
if (m_event->getX() != x) {
|
||||
m_event->setX(x);
|
||||
emit xChanged(x);
|
||||
changed = true;
|
||||
}
|
||||
if (m_event->getY() != y) {
|
||||
m_event->setY(y);
|
||||
emit yChanged(y);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
updatePixelPosition();
|
||||
emit posChanged(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void EventPixmapItem::updatePixelPosition() {
|
||||
setPos(m_event->getPixelX(), m_event->getPixelY());
|
||||
}
|
||||
|
||||
void EventPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) {
|
||||
if (m_active)
|
||||
return;
|
||||
m_active = true;
|
||||
m_lastPos = Metatile::coordFromPixmapCoord(mouseEvent->scenePos());
|
||||
|
||||
bool selectionToggle = mouseEvent->modifiers() & Qt::ControlModifier;
|
||||
if (selectionToggle || !m_selected) {
|
||||
// User is either toggling this selection on/off as part of a group selection,
|
||||
// or they're newly selecting just this item.
|
||||
m_selected = (selectionToggle) ? !m_selected : true;
|
||||
emit selected(m_event, selectionToggle);
|
||||
} else {
|
||||
// This item is already selected and the user isn't toggling the selection, so there are 4 possibilities:
|
||||
// 1. This is the only selected event, and the selection is pointless.
|
||||
// 2. This is the only selected event, and they want to drag the item around.
|
||||
// 3. There's a group selection, and they want to start a new selection with just this item.
|
||||
// 4. There's a group selection, and they want to drag the group around.
|
||||
// 'selectMapEvent' will immediately clear the rest of the selection, which supports #1-3 but prevents #4.
|
||||
// To support #4 we set the flag below, and we only call 'selectMapEvent' on mouse release if no move occurred.
|
||||
m_releaseSelectionQueued = true;
|
||||
}
|
||||
mouseEvent->accept();
|
||||
}
|
||||
|
||||
void EventPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) {
|
||||
if (!m_active || !m_selected)
|
||||
return;
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(mouseEvent->scenePos());
|
||||
if (pos == m_lastPos)
|
||||
return;
|
||||
|
||||
m_releaseSelectionQueued = false;
|
||||
emit dragged(m_event, m_lastPos, pos);
|
||||
m_lastPos = pos;
|
||||
}
|
||||
|
||||
void EventPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) {
|
||||
if (!m_active)
|
||||
return;
|
||||
m_active = false;
|
||||
if (m_releaseSelectionQueued) {
|
||||
m_releaseSelectionQueued = false;
|
||||
if (Metatile::coordFromPixmapCoord(mouseEvent->scenePos()) == m_lastPos)
|
||||
emit selected(m_event, false);
|
||||
}
|
||||
emit released(m_event, m_lastPos);
|
||||
}
|
||||
|
|
@ -2,22 +2,7 @@
|
|||
#include "mapview.h"
|
||||
#include "editor.h"
|
||||
|
||||
void GraphicsView::mousePressEvent(QMouseEvent *event) {
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
if (editor) {
|
||||
editor->eventsView_onMousePress(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsView::mouseMoveEvent(QMouseEvent *event) {
|
||||
QGraphicsView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void GraphicsView::mouseReleaseEvent(QMouseEvent *event) {
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GraphicsView::moveEvent(QMoveEvent *event) {
|
||||
void MapView::moveEvent(QMoveEvent *event) {
|
||||
QGraphicsView::moveEvent(event);
|
||||
QLabel *label_MapRulerStatus = findChild<QLabel *>("label_MapRulerStatus", Qt::FindDirectChildrenOnly);
|
||||
if (label_MapRulerStatus && label_MapRulerStatus->isVisible())
|
||||
|
|
|
|||
|
|
@ -714,19 +714,20 @@ void LayoutPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
|
|||
}
|
||||
|
||||
void LayoutPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
this->paint_tile_initial_x = this->straight_path_initial_x = pos.x();
|
||||
this->paint_tile_initial_y = this->straight_path_initial_y = pos.y();
|
||||
this->metatilePos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
this->paint_tile_initial_x = this->straight_path_initial_x = this->metatilePos.x();
|
||||
this->paint_tile_initial_y = this->straight_path_initial_y = this->metatilePos.y();
|
||||
emit startPaint(event, this);
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
void LayoutPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(event->pos());
|
||||
if (pos != this->metatilePos) {
|
||||
this->metatilePos = pos;
|
||||
emit this->hoveredMapMetatileChanged(pos);
|
||||
}
|
||||
if (pos == this->metatilePos)
|
||||
return;
|
||||
|
||||
this->metatilePos = pos;
|
||||
emit hoveredMapMetatileChanged(pos);
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ void MapImageExporter::setModeSpecificUi() {
|
|||
}
|
||||
|
||||
if (m_mode == ImageExporterMode::Timelapse) {
|
||||
// TODO: At the moment edit history for events (and the DraggablePixmapItem class)
|
||||
// explicitly depend on the editor and assume their map is currently open.
|
||||
// TODO: At the moment edit history for events explicitly depend on the editor and assume their map is currently open.
|
||||
// Other edit commands rely on this more subtly, like triggering API callbacks or
|
||||
// spending time rendering their layout (which can make creating timelapses very slow).
|
||||
// Until this is resolved, the selected map/layout must remain the same as in the editor.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ ResizableRect::ResizableRect(QObject *parent, bool *enabled, int width, int heig
|
|||
: QObject(parent),
|
||||
MovableRect(enabled, QRect(0, 0, width * 16, height * 16), color)
|
||||
{
|
||||
setZValue(0xFFFFFFFF); // ensure on top of view
|
||||
setAcceptHoverEvents(true);
|
||||
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ void ResizeLayoutPopup::setupLayoutView() {
|
|||
static bool layoutSizeRectVisible = true;
|
||||
|
||||
this->outline = new ResizableRect(this, &layoutSizeRectVisible, this->editor->layout->getWidth(), this->editor->layout->getHeight(), qRgb(255, 0, 255));
|
||||
this->outline->setZValue(Editor::ZValue::ResizeLayoutPopup); // Ensure on top of view
|
||||
this->outline->setLimit(cover->rect().toAlignedRect());
|
||||
connect(outline, &ResizableRect::rectUpdated, [=](QRect rect){
|
||||
// Note: this extra limit check needs access to the project values, so it is done here and not ResizableRect::mouseMoveEvent
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user