From a9098cfd7a228f67aa9569588eb857a730bcb78c Mon Sep 17 00:00:00 2001 From: garak Date: Fri, 4 Jan 2019 23:04:14 -0500 Subject: [PATCH] add layout view to region map editor --- forms/mainwindow.ui | 228 ++++++++++++---------- include/core/regionmapeditor.h | 92 ++++----- include/editor.h | 20 +- include/mainwindow.h | 1 + include/project.h | 3 + include/ui/regionmaplayoutpixmapitem.h | 42 ++++ include/ui/tilemaptileselector.h | 2 +- porymap.pro | 2 + src/core/regionmapeditor.cpp | 257 +++++++++++++------------ src/editor.cpp | 147 +++++++++++++- src/mainwindow.cpp | 13 ++ src/project.cpp | 1 + src/ui/regionmaplayoutpixmapitem.cpp | 85 ++++++++ src/ui/tilemaptileselector.cpp | 40 +--- 14 files changed, 597 insertions(+), 336 deletions(-) create mode 100644 include/ui/regionmaplayoutpixmapitem.h create mode 100644 src/ui/regionmaplayoutpixmapitem.cpp diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index c1e76938..02a3969c 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -237,7 +237,7 @@ - 4 + 0 false @@ -2778,7 +2778,7 @@ - + true @@ -2847,10 +2847,10 @@ - 30 - 20 - 321 - 211 + 0 + 0 + 371 + 261 @@ -2867,8 +2867,8 @@ 0 0 - 319 - 209 + 369 + 259 @@ -2972,10 +2972,10 @@ - 20 - 20 - 321 - 211 + 0 + 0 + 371 + 261 @@ -2992,8 +2992,8 @@ 0 0 - 319 - 209 + 369 + 259 @@ -3357,20 +3357,20 @@ - + false - 50 - 40 - 261 - 170 + 10 + 30 + 331 + 211 - + 0 0 @@ -3381,93 +3381,107 @@ QFrame::Raised - - - - - Connected Map - - - - - - - <html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is display when the player enters it.</p></body></html> - - - true - - - - - - - Weather - - - - - - - <html><head/><body><p>The default weather for this map.</p></body></html> - - - true - - - - - - - Type - - - - - - - <html><head/><body><p>The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.</p></body></html> - - - true - - - - - - - Show Location Name - - - - - - - <html><head/><body><p>Whether or not to display the location name when the player enters the map.</p></body></html> - - - - - - - - - - Battle scene - - - - - - - <html><head/><body><p>Determines the type of battle scene graphics to use.</p></body></html> - - - true - - - - + + + + 210 + 170 + 107 + 32 + + + + Set Values + + + + + + 13 + 11 + 301 + 111 + + + + + + + Map Section + + + + + + + <html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is display when the player enters it.</p></body></html> + + + true + + + + + + + Map Name + + + + + + + + + + City Map + + + + + + + <html><head/><body><p>The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.</p></body></html> + + + true + + + + + + + + + 20 + 130 + 121 + 26 + + + + + + + x + + + + + + + + + + y + + + + + + + + diff --git a/include/core/regionmapeditor.h b/include/core/regionmapeditor.h index 2875ef81..a16e77f1 100644 --- a/include/core/regionmapeditor.h +++ b/include/core/regionmapeditor.h @@ -4,7 +4,6 @@ #include "project.h" #include "map.h" #include "tilemaptileselector.h" -//#include "block.h" #include #include @@ -13,48 +12,28 @@ #include #include -// if editing map bins, will need to remake the graphics when editing -// are the scenes set in the editor / project / mainwindow files? -/* - * - display the region map background image - * - edit the region_map_layout.h layout - * - edit city maps metatile layout and JUST save the mapname_num.bin - * - edit - * who edits pokenav_city_maps 1 and 2? - * users can: - add the incbins probably themselves - * - add - * - edit region map background image - * - * - * - * - * Editor: - * - void displayCityMapMetatileSelector - * - void displayRegionMapTileSelector - * - void selectRegionMapTile(QString mapname) - * - QGraphicsScene *scene_city_map_metatiles - * - TilemapTileSelector *city_map_metatile_selector_item - * - Tileset *city_map_squares (or tileset_city_map?) - * - Tileset *tileset_region_map - * - * MainWindow: - * - * - * Project: - * - */ -// rename this struct +// rename this struct? struct CityMapPosition { // - //QString filename; // eg. dewford_0 + //QString filename; // eg. dewford_0 ? QString tilemap;// eg. "dewford_0" int x; int y; }; +struct RegionMapEntry +{ + // + int x; + int y; + int width; + int height; + QString name;// mapsection +}; + // class that holds data for each square in this project // struct? // TODO: change char / uint8_t to unsigned @@ -62,17 +41,14 @@ class RegionMapSquare { public: // - // are positions layout positions? (yes) so out of bounds are all (-1, -1) <-- how it's used in code - // (GetRegionMapLocationPosition) - // or image positions int x = -1;// x position, 0-indexed from top left int y = -1;// y position, 0-indexed from top left uint8_t tile_img_id;// tilemap ids for the background image bool has_map = false;// whether this square is linked to a map or is empty - QString map_name;// name of the map associated with this square (if has_map is true): eg. "MAUVILLE_CITY" - // ^ use project mapsec to names table - bool has_city_map;// whether there is a city map on this grid - //QList city_maps; + QString map_name;// name of the map associated with this square (if has_map is true): eg. "MAUVILLE_CITY" (TODO: REMOVE) + QString mapsec; + uint8_t secid; + bool has_city_map = false;// whether there is a city map on this grid QString city_map_name;// filename of the city_map tilemap //bool is_flyable;//? needed ? friend class RegionMap;// not necessary if instance? what @@ -87,17 +63,13 @@ class RegionMap : public QObject public: RegionMap() = default; - ~RegionMap() { - delete mapname_abbr; - delete layout_map_names; - //delete background_image_tiles; - //delete map_squares; - //delete background_image_selector_item; - }; + ~RegionMap() {}; static QMap> ruby_city_maps_; static QString mapSecToMapConstant(QString); + Project *project; + //RegionMapSquare *map_squares = nullptr;// array of RegionMapSquares QList map_squares; @@ -107,16 +79,16 @@ public: QString region_map_bin_path;// = QString::null; QString city_map_header_path;//dafuq is this? QString region_map_layout_path; + QString region_map_entries_path; + QString region_map_layout_bin_path; + QString region_map_city_map_tiles_path; - //QMap something;// name of map : info about city map, position in layoit, etc. - //QMap regionMapLayoutTng; // mapName : tilemaptileselector - // maybe position data to select correct square when changing map on side but only if map is a valid - //QList *background_image_tiles;// the visible ones anyways // using list because replace - //TilemapTileSelector *background_image_selector_item;// ? - QMap *mapname_abbr;// layout shortcuts mapname:region_map_layout defines (both ways) - // make this a QHash?? <-- no because something - QStringList *layout_map_names; - // uint8_t border_tile; + QByteArray mapBinData; + + QMap sMapNames;// {"{/sMapName_/}LittlerootTown" : "LITTLEROOT{NAME_END} TOWN"} + QMap mapSecToMapName;// {"MAPSEC_LITTLEROOT_TOWN" : "LITTLEROOT{NAME_END} TOWN"} + //QList> mapSecToMapEntry; + QMap mapSecToMapEntry;// TODO: add to this on creation of new map bool hasUnsavedChanges(); @@ -125,7 +97,7 @@ public: // parseutil.cpp ? void readBkgImgBin(); void readCityMaps();// more complicated - void readLayout(QMap*); + void readLayout(); QString newAbbr(QString);// makes a *unique* 5 character abbreviation from mapname to add to mapname_abbr @@ -140,6 +112,7 @@ public: void save(); void saveBkgImgBin(); void saveLayout(); + void saveOptions(int, QString, QString, int, int); void saveCityMaps(); void update();// update the view in case something is broken? @@ -150,12 +123,13 @@ public: int height(); QSize imgSize(); unsigned getTileId(int, int); + int getMapSquareIndex(int, int); // implement these here? void undo(); void redo(); - void test(QMap*);// remove when done testing obvi + void test();// remove when done testing obvi // TODO: move read / write functions to private (and others) private: @@ -166,6 +140,8 @@ private: int img_height_; int img_index_(int, int);// returns index int at x,y args (x + y * width_ * 2) // 2 because int layout_index_(int, int); + void fillMapSquaresFromLayout(); + QString fix_case(QString);// CAPS_WITH_UNDERSCORE to CamelCase //protected: // diff --git a/include/editor.h b/include/editor.h index b28f0ebf..f84600b9 100644 --- a/include/editor.h +++ b/include/editor.h @@ -20,6 +20,7 @@ #include "collisionpixmapitem.h" #include "mappixmapitem.h" #include "regionmappixmapitem.h" +#include "regionmaplayoutpixmapitem.h" #include "regionmapeditor.h" #include "settings.h" #include "movablerect.h" @@ -79,31 +80,42 @@ public: void updateCustomMapHeaderValues(QTableWidget *); Tileset *getCurrentMapPrimaryTileset(); -// +// TODO: move these to appropriate place RegionMap *region_map; void loadRegionMapData(); QGraphicsScene *scene_region_map_image = nullptr; - QGraphicsScene *scene_region_map_layout = nullptr;//? + QGraphicsScene *scene_region_map_layout = nullptr; QGraphicsScene *scene_region_map_tiles = nullptr; + QGraphicsScene *scene_city_map_tiles = nullptr; TilemapTileSelector *mapsquare_selector_item = nullptr; + TilemapTileSelector *city_map_selector_item = nullptr; RegionMapPixmapItem *region_map_item = nullptr; + RegionMapLayoutPixmapItem *region_map_layout_item = nullptr; void displayRegionMap(); + void displayRegionMapImage(); + void displayRegionMapLayout(); + void displayRegionMapLayoutOptions(); + void updateRegionMapLayoutOptions(int); void displayRegionMapTileSelector(); + void displayCityMapTileSelector(); - // selectedTileChanged, hoveredTileChanged, hoveredTileCleared void onRegionMapTileSelectorSelectedTileChanged(); void onRegionMapTileSelectorHoveredTileChanged(unsigned); void onRegionMapTileSelectorHoveredTileCleared(); + void onRegionMapLayoutSelectedTileChanged(int); + void onRegionMapLayoutHoveredTileChanged(int); + void onRegionMapLayoutHoveredTileCleared(); + private slots: void onHoveredRegionMapTileChanged(int, int); void onHoveredRegionMapTileCleared(); void mouseEvent_region_map(QGraphicsSceneMouseEvent *, RegionMapPixmapItem *); public: - QString regionMapTabStatusbarMessage;// TODO: make this name not terrible + QString rmStatusbarMessage; // DraggablePixmapItem *addMapEvent(Event *event); diff --git a/include/mainwindow.h b/include/mainwindow.h index 3cbe1fc0..1f5c3eb5 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -68,6 +68,7 @@ private slots: void on_tabWidget_Region_Map_currentChanged(int); void on_tabWidget_currentChanged(int index); + void on_pushButton_RM_Options_save_clicked(); void on_actionUndo_triggered(); diff --git a/include/project.h b/include/project.h index 89306895..5331b6aa 100644 --- a/include/project.h +++ b/include/project.h @@ -47,6 +47,9 @@ public: Map* loadMap(QString); Map* getMap(QString); + // other options include: InGameName, PopUpName, ???? + QMap *mapSecToMapHoverName;// {"MAPSEC_LITTLEROOT_TOWN" : "LITTLEROOT{NAME_END} TOWN"} + QMap *tileset_cache = nullptr; Tileset* loadTileset(QString, Tileset *tileset = nullptr); Tileset* getTileset(QString, bool forceLoad = false); diff --git a/include/ui/regionmaplayoutpixmapitem.h b/include/ui/regionmaplayoutpixmapitem.h new file mode 100644 index 00000000..1fca1581 --- /dev/null +++ b/include/ui/regionmaplayoutpixmapitem.h @@ -0,0 +1,42 @@ +#ifndef REGIONMAPLAYOUTPIXMAPITEM_H +#define REGIONMAPLAYOUTPIXMAPITEM_H + +#include "tilemaptileselector.h" +//#include "regionmappixmapitem.h" +#include "regionmapeditor.h" + +class RegionMapLayoutPixmapItem : public SelectablePixmapItem { + Q_OBJECT +public: + RegionMapLayoutPixmapItem(RegionMap *rmap, TilemapTileSelector *ts) : SelectablePixmapItem(8, 8, 1, 1) { + // + this->region_map = rmap; + this->tile_selector = ts; + setAcceptHoverEvents(true); + } + RegionMap *region_map;// inherited from RegionMapPixmapItem? + TilemapTileSelector *tile_selector; + int selectedTile;// index in map_squares + void draw(); + void select(int, int); + void setDefaultSelection(); + +private: + void updateSelectedTile(); + +// can I implement these if they are virtual? +signals: + void mouseEvent(QGraphicsSceneMouseEvent *, RegionMapLayoutPixmapItem *); + void hoveredTileChanged(int); + void hoveredTileCleared(); + void selectedTileChanged(int); + +protected: + void hoverMoveEvent(QGraphicsSceneHoverEvent*); + void hoverLeaveEvent(QGraphicsSceneHoverEvent*); + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); +}; + +#endif // REGIONMAPLAYOUTPIXMAPITEM_H diff --git a/include/ui/tilemaptileselector.h b/include/ui/tilemaptileselector.h index 8bb52050..1bf94984 100644 --- a/include/ui/tilemaptileselector.h +++ b/include/ui/tilemaptileselector.h @@ -8,7 +8,7 @@ class TilemapTileSelector: public SelectablePixmapItem { public: TilemapTileSelector(QPixmap pixmap): SelectablePixmapItem(8, 8, 1, 1) { this->pixmap = pixmap; - this->numTilesWide = 16; + this->numTilesWide = pixmap.width() / 8; this->selectedTile = 0x00; setAcceptHoverEvents(true); } diff --git a/porymap.pro b/porymap.pro index 3868a8a2..98ba5e2e 100644 --- a/porymap.pro +++ b/porymap.pro @@ -34,6 +34,7 @@ SOURCES += src/core/block.cpp \ src/ui/collisionpixmapitem.cpp \ src/ui/connectionpixmapitem.cpp \ src/ui/currentselectedmetatilespixmapitem.cpp \ + src/ui/regionmaplayoutpixmapitem.cpp \ src/ui/cursortilerect.cpp \ src/ui/customattributestable.cpp \ src/ui/eventpropertiesframe.cpp \ @@ -87,6 +88,7 @@ HEADERS += include/core/block.h \ include/ui/collisionpixmapitem.h \ include/ui/connectionpixmapitem.h \ include/ui/currentselectedmetatilespixmapitem.h \ + include/ui/regionmaplayoutpixmapitem.h \ include/ui/cursortilerect.h \ include/ui/customattributestable.h \ include/ui/eventpropertiesframe.h \ diff --git a/src/core/regionmapeditor.cpp b/src/core/regionmapeditor.cpp index 73b27c0f..1242500f 100644 --- a/src/core/regionmapeditor.cpp +++ b/src/core/regionmapeditor.cpp @@ -83,8 +83,10 @@ QMap> RegionMap::ruby_city_maps_ = QMaproot; + this->project = pro; // // TODO: in the future, allow these to be adjustable (and save values) // possibly use a config file? @@ -99,20 +101,24 @@ void RegionMap::init(Project *pro) { region_map_bin_path = path + "/graphics/pokenav/region_map_map.bin"; region_map_png_path = path + "/graphics/pokenav/region_map.png"; region_map_layout_path = path + "/src/data/region_map_layout.h"; + region_map_entries_path = path + "/src/data/region_map/region_map_entries.h"; + region_map_layout_bin_path = path + "/graphics/pokenav/region_map_section_layout.bin"; + region_map_city_map_tiles_path = path + "/graphics/pokenav/zoom_tiles.png";// TODO: rename png to map_squares in pokeemerald readBkgImgBin(); - readLayout(pro->mapConstantsToMapNames); + readLayout(); readCityMaps(); //tryGetMap(); //saveBkgImgBin(); //saveLayout(); - test(pro->mapConstantsToMapNames); + + //test(); } // as of now, this needs to be called first because it initializes all the -// RegionMapSquare s in the list +// `RegionMapSquare`s in the list // TODO: if the tileId is not valid for the provided image, make sure it does not crash void RegionMap::readBkgImgBin() { QFile binFile(region_map_bin_path); @@ -121,7 +127,7 @@ void RegionMap::readBkgImgBin() { QByteArray mapBinData = binFile.readAll(); binFile.close(); - // the two is because lines are skipped for some reason + // the two multiplier is because lines are skipped for some reason // (maybe that is because there could be multiple layers?) // background image is also 32x20 for (int m = 0; m < img_height_; m++) { @@ -148,113 +154,123 @@ void RegionMap::saveBkgImgBin() { file.close(); } -// done -void RegionMap::readLayout(QMap *qmap) { - QFile file(region_map_layout_path); +// TODO: reorganize this into project? the i/o stuff. use regionMapSections +void RegionMap::readLayout() { + // + QFile file(region_map_entries_path); if (!file.open(QIODevice::ReadOnly)) return; - QMap * abbr = new QMap; + QString line; + // TODO: put these in Project, and keep in order + //QMap sMapNames;// {"sMapName_LittlerootTown" : "LITTLEROOT{NAME_END} TOWN"} + //QMap mapSecToMapName;// {"MAPSEC_LITTLEROOT_TOWN" : "LITTLEROOT{NAME_END} TOWN"} + //QList<> mapSecToMapEntry;// {"MAPSEC_LITTLEROOT_TOWN" : } - QString line, text; - QStringList *captured = new QStringList; + // new map ffor mapSecToMapHoverName + QMap *qmap = new QMap; QTextStream in(&file); while (!in.atEnd()) { line = in.readLine(); - if (line.startsWith("#define")) { - QStringList split = line.split(QRegularExpression("\\s+")); - abbr->insert(split[2].replace("MAPSEC_",""), split[1]); - } else { - text += line.remove(" "); + if (line.startsWith("static const u8")) { + QRegularExpression reBefore("sMapName_(.*)\\["); + QRegularExpression reAfter("_\\(\"(.*)\""); + QString const_name = reBefore.match(line).captured(1); + QString full_name = reAfter.match(line).captured(1); + sMapNames.insert(const_name, full_name); + } else if (line.contains("MAPSEC")) { + QRegularExpression reBefore("\\[(.*)\\]"); + QRegularExpression reAfter("{(.*)}"); + QStringList entry = reAfter.match(line).captured(1).remove(" ").split(","); + QString mapsec = reBefore.match(line).captured(1); + QString insertion = entry[4].remove("sMapName_"); + qmap->insert(mapsec, sMapNames[insertion]); + // can make this a map, the order doesn't really matter + mapSecToMapEntry[mapsec] = + // x y width height name + {entry[0].toInt(), entry[1].toInt(), entry[2].toInt(), entry[3].toInt(), insertion} + ; + // ^ when loading this info to city maps, loop over mapSecToMapEntry and + // add x and y map sqyare when width or height >1 + // indexOf because mapsecs is just a qstringlist + //text += line.remove(" "); } } - QRegularExpression re("{(.*?)}"); - *captured = re.match(text).captured(1).split(","); - captured->removeAll({}); + file.close(); - // replace abbreviations with names - for (int i = 0; i < captured->length(); i++) { - QString value = (*captured)[i]; - if (value.startsWith("R(")) {// routes are different - captured->replace(i, QString("ROUTE_%1").arg(value.mid(2,3))); - } else { - captured->replace(i, abbr->key(value)); - } - } + project->mapSecToMapHoverName = qmap; + + QFile binFile(region_map_layout_bin_path); + if (!binFile.open(QIODevice::ReadOnly)) return; + QByteArray mapBinData = binFile.readAll(); + binFile.close(); // TODO: improve this? - for (int m = 0, i = 0; m < layout_height_; m++) { + for (int m = 0; m < layout_height_; m++) { for (int n = 0; n < layout_width_; n++) { - i = img_index_(n,m); - QString secname = (*captured)[layout_index_(n,m)]; - if (secname != "NOTHING") map_squares[i].has_map = true; - map_squares[i].map_name = qmap->value(mapSecToMapConstant(secname)); + int i = img_index_(n,m); + map_squares[i].secid = static_cast(mapBinData.at(layout_index_(n,m))); + QString secname = (*(project->regionMapSections))[static_cast(mapBinData.at(layout_index_(n,m)))]; + //qDebug() << i << map_squares[i].secid << secname; + if (secname != "MAPSEC_NONE") map_squares[i].has_map = true; + map_squares[i].mapsec = secname; + map_squares[i].map_name = sMapNames.value(mapSecToMapEntry.value(secname).name);//[mapSecToMapEntry[secname].name]; map_squares[i].x = n; map_squares[i].y = m; } } - mapname_abbr = abbr; - layout_map_names = captured; - file.close(); } -// does it matter that it doesn't save in order? -// do i need to use a QList ?? +/// saves: +// region_map_entries_path +// region_map_layout_bin_path (layout as tilemap instead of how it is in ruby) +// done +// TODO: consider keeping QMaps in order void RegionMap::saveLayout() { - // - QString layout_text = ""; - QString mapsec = "MAPSEC_"; - QString define = "#define "; - QString array_start = "static const u8 sRegionMapLayout[] =\n{"; - QString array_close = "\n};\n"; - QString tab = " "; + QString entries_text; + QString layout_text; - for (QString key : mapname_abbr->keys()) { - layout_text += define + mapname_abbr->value(key) + tab + mapsec + key + "\n"; + entries_text += "#ifndef GUARD_DATA_REGION_MAP_REGION_MAP_ENTRIES_H\n"; + entries_text += "#define GUARD_DATA_REGION_MAP_REGION_MAP_ENTRIES_H\n\n"; + + // note: this doesn't necessarily keep order because it is a QMap + for (auto it : this->project->mapSecToMapHoverName->keys()) { + entries_text += "static const u8 sMapName_" + fix_case(it) + "[] = _(\"" + this->project->mapSecToMapHoverName->value(it) + "\");\n"; } - layout_text += "\n" + array_start;// + + array_close;//oops + entries_text += "\nconst struct RegionMapLocation gRegionMapEntries[] = {\n"; - //qDebug() << *layout_map_names; - int cnt = 0; - for (QString s : *layout_map_names) { - // - if (!(cnt % layout_width_)) { - layout_text += "\n" + tab; - } - if (s.startsWith("ROUTE_")) { - layout_text += QString("R(%1)").arg(s.replace("ROUTE_","")) + ", "; - } else { - layout_text += mapname_abbr->value(s) + ", "; - } - cnt++; + for (auto sec : mapSecToMapEntry.keys()) { + struct RegionMapEntry entry = mapSecToMapEntry.value(sec); + entries_text += " [" + sec + "] = {" + QString::number(entry.x) + ", " + QString::number(entry.y) + ", " + + QString::number(entry.width) + ", " + QString::number(entry.height) + ", sMapName_" + fix_case(sec) + "},\n";//entry.name } + entries_text += "};\n\n#endif // GUARD_DATA_REGION_MAP_REGION_MAP_ENTRIES_H\n"; - //layout_text. - layout_text += array_close; - - QFile file(region_map_layout_path); - if (!file.open(QIODevice::WriteOnly)) return; - file.write(layout_text.toUtf8()); - file.close(); + project->saveTextFile(region_map_entries_path, entries_text); + + QByteArray data; + for (int m = 0; m < layout_height_; m++) { + for (int n = 0; n < layout_width_; n++) { + int i = img_index_(n,m); + data.append(map_squares[i].secid); + } + } + QFile bfile(region_map_layout_bin_path); + if (!bfile.open(QIODevice::WriteOnly)) return; + bfile.write(data); + bfile.close(); } +// beyond broken void RegionMap::readCityMaps() { // - //for (int m = 0; m < layout_height_; m++) { - // QString tester; - // for (int n = 0; n < layout_width_; n++) { - // tester += (QString::number(img_index_(n,m)).rightJustified(3, '.') + " "); - // } - // qDebug() << tester; - //} - //for (auto map : map_squares) { for (int map = 0; map < map_squares.size(); map++) { // if (map_squares[map].has_map) { // if (ruby_city_maps_.contains(map_squares[map].map_name)) { - map_squares[map].has_city_map = true; + //map_squares[map].has_city_map = true; //map_squares[map].city_map_name = ruby_city_maps_.value(map_squares[map].map_name)[0].tilemap; QList city_maps = ruby_city_maps_.value(map_squares[map].map_name); for (auto city_map : city_maps) { @@ -262,6 +278,7 @@ void RegionMap::readCityMaps() { if (city_map.x == map_squares[map].x && city_map.y == map_squares[map].y) // + map_squares[map].has_city_map = true; map_squares[map].city_map_name = city_map.tilemap; } } @@ -269,27 +286,6 @@ void RegionMap::readCityMaps() { } } -//done -QString RegionMap::newAbbr(QString mapname) { - QString abbr; - QStringList words = mapname.split("_"); - - if (words.length() == 1) { - abbr = (words[0] + "_____X").left(6); - } else { - abbr = (words.front() + "___X").left(4) + "_" + words.back().at(0); - } - - // to guarantee unique abbreviations (up to 14) - QString extra_chars = "23456789BCDEF"; - int count = 0; - while ((*mapname_abbr).values().contains(abbr)) { - abbr.replace(5,1,extra_chars[count]); - count++; - } - return abbr; -} - // layout coords to image index int RegionMap::img_index_(int x, int y) { return ((x + 1) + (y + 2) * img_width_); @@ -300,10 +296,7 @@ int RegionMap::layout_index_(int x, int y) { return (x + y * layout_width_); } -// img coords to layout index? -// img coords to img index? - -void RegionMap::test(QMap* qmap) { +void RegionMap::test() { // bool debug_rmap = false; @@ -316,17 +309,11 @@ void RegionMap::test(QMap* qmap) { << square.has_city_map << square.city_map_name ; - //if (qmap->contains(mapSecToMapConstant(square.map_name))) - // extras += qmap->value(mapSecToMapConstant(square.map_name)) + " "; - //else - // extras += "nothing "; } QPixmap png(region_map_png_path); - //png.load(region_map_png_path); qDebug() << "png num 8x8 tiles" << QString("0x%1").arg((png.width()/8) * (png.height() / 8), 2, 16, QChar('0')); } - } int RegionMap::width() { @@ -346,26 +333,57 @@ QSize RegionMap::imgSize() { unsigned RegionMap::getTileId(int x, int y) { // return map_squares[x + y * img_width_].tile_img_id; - //qDebug() << x << y; - //return 0; } -// sidenote: opening the map from MAPSEC_x will not always be right -// there needs to be a mapsections to mapname QMap -// otherwie, look for the first map with right substring -// mapConstantsToMapNames [MAP_ROUTE106] = "Route106" -// eg. SOUTHERN_ISLAND -> MAP_SOUTHERN_ISLAND -> SouthernIsland(n) -> SouthernIsland_Exterior -// MT_CHIMNEY -> MAP_MT_CHIMNEY -> MtChimney(y) -// ROUTE_101 -> MAP_ROUTE101 -> Route101(y) -// (or synchronize these for consistency in the repos :: underscore / no underscore) - // TODO: change debugs to logs void RegionMap::save() { // qDebug() << "saving region map image tilemap at" << region_map_bin_path << "\n" - ;//<< "saving region map layout at" << region_map_layout_path << "\n"; + << "saving region map layout at" << region_map_layout_path << "\n" + ; saveBkgImgBin(); + saveLayout(); +} + +// save Options (temp) +void RegionMap::saveOptions(int index, QString sec, QString name, int x, int y) { + // + // TODO:req need to reindex in city_maps if changing x and y + // TODO: save [sec] sMapName_ properly + // so instead of taking index, maybe go by img_index_(x,y) + this->project->mapSecToMapHoverName->insert(sec, name); + this->map_squares[index].mapsec = sec; + this->map_squares[index].map_name = name;// TODO: display in editor with this map & remove this field + this->map_squares[index].x = x; + this->map_squares[index].y = y; +} + +// from x, y of image +// TODO: make sure this returns a valid index +int RegionMap::getMapSquareIndex(int x, int y) { + // + int index = (x + y * img_width_); + return index < map_squares.length() - 1 ? index : 0; +} + +// For turning a MAPSEC_NAME into a unique identifier sMapName-style variable. +QString RegionMap::fix_case(QString caps) { + bool big = true; + QString camel; + + for (auto ch : caps.remove(QRegularExpression("({.*})")).remove("MAPSEC")) { + if (ch == '_' || ch == ' ') { + big = true; + continue; + } + if (big) { + camel += ch.toUpper(); + big = false; + } + else camel += ch.toLower(); + } + return camel; } @@ -397,6 +415,5 @@ void RegionMap::save() { - diff --git a/src/editor.cpp b/src/editor.cpp index 9cfce50e..86680762 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -453,6 +453,17 @@ bool Editor::setMap(QString map_name) { selected_events->clear(); displayMap(); updateSelectedEvents(); + + if (region_map) { + for (auto square : region_map->map_squares) { + if (square.mapsec == map->location) { + int img_x = square.x + 1; + int img_y = square.y + 2; + this->region_map_layout_item->select(img_x, img_y); + break; + } + } + } } return true; @@ -602,6 +613,7 @@ void Editor::displayMap() { displayMapBorder(); displayMapGrid(); +<<<<<<< abc873464dc736dcfdda4a20df61516f45478844 this->playerViewRect->setZValue(1000); this->cursorMapTileRect->setZValue(1001); scene->addItem(this->playerViewRect); @@ -610,6 +622,8 @@ void Editor::displayMap() { displayRegionMapTileSelector();//? displayRegionMap(); +======= +>>>>>>> add layout view to region map editor if (map_item) { map_item->setVisible(false); } @@ -621,6 +635,14 @@ void Editor::displayMap() { } } +void Editor::displayRegionMap() { + displayRegionMapTileSelector(); + displayCityMapTileSelector(); + displayRegionMapImage(); + displayRegionMapLayout(); + displayRegionMapLayoutOptions(); +} + void Editor::displayMetatileSelector() { if (metatile_selector_item && metatile_selector_item->scene()) { metatile_selector_item->scene()->removeItem(metatile_selector_item); @@ -1273,7 +1295,8 @@ void Editor::deleteEvent(Event *event) { void Editor::loadRegionMapData() { // - region_map->init(project); + this->region_map->init(project); + displayRegionMap(); } // TODO: get this to display on a decent scale @@ -1297,8 +1320,29 @@ void Editor::displayRegionMapTileSelector() { this->mapsquare_selector_item->pixelHeight + 2); } +void Editor::displayCityMapTileSelector() { + // city_map_selector_item + this->city_map_selector_item = new TilemapTileSelector(QPixmap(this->region_map->region_map_city_map_tiles_path)); + this->city_map_selector_item->draw(); + + this->scene_city_map_tiles = new QGraphicsScene; + this->scene_city_map_tiles->addItem(this->city_map_selector_item); + + /*connect(this->city_map_selector_item, &TilemapTileSelector::selectedTileChanged, + this, &Editor::onRegionMapTileSelectorSelectedTileChanged);// TODO: remove this? + connect(this->city_map_selector_item, &TilemapTileSelector::hoveredTileChanged, + this, &Editor::onRegionMapTileSelectorHoveredTileChanged); + connect(this->city_map_selector_item, &TilemapTileSelector::hoveredTileCleared, + this, &Editor::onRegionMapTileSelectorHoveredTileCleared);*/ + + this->ui->graphicsView_City_Map_Tiles->setScene(this->scene_city_map_tiles); + this->ui->graphicsView_City_Map_Tiles->setFixedSize(this->city_map_selector_item->pixelWidth + 2, + this->city_map_selector_item->pixelHeight + 2); +} + // TODO: change the signal slot to new syntax -void Editor::displayRegionMap() { +// TODO: add scalability? +void Editor::displayRegionMapImage() { // this->region_map_item = new RegionMapPixmapItem(this->region_map, this->mapsquare_selector_item); connect(region_map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*, RegionMapPixmapItem*)), @@ -1313,10 +1357,51 @@ void Editor::displayRegionMap() { this->scene_region_map_image->addItem(this->region_map_item); this->scene_region_map_image->setSceneRect(this->scene_region_map_image->sceneRect()); - //this->scene_region_map_image->scale(2, 2); this->ui->graphicsView_Region_Map_BkgImg->setScene(this->scene_region_map_image); this->ui->graphicsView_Region_Map_BkgImg->setFixedSize(this->region_map->imgSize()); - //this->ui->graphicsView_Region_Map_BkgImg->scale(2.0, 2.0); +} + +void Editor::displayRegionMapLayout() { + // + this->region_map_layout_item = new RegionMapLayoutPixmapItem(this->region_map, this->mapsquare_selector_item); + //* + connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::selectedTileChanged, + this, &Editor::onRegionMapLayoutSelectedTileChanged);// TODO: remove this? + connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::hoveredTileChanged, + this, &Editor::onRegionMapLayoutHoveredTileChanged); + connect(this->region_map_layout_item, &RegionMapLayoutPixmapItem::hoveredTileCleared, + this, &Editor::onRegionMapLayoutHoveredTileCleared); + //*/ + this->region_map_layout_item->draw(); + this->region_map_layout_item->setDefaultSelection(); + + this->scene_region_map_layout = new QGraphicsScene; + this->scene_region_map_layout->addItem(region_map_layout_item); + this->scene_region_map_layout->setSceneRect(this->scene_region_map_layout->sceneRect()); + + this->ui->graphicsView_Region_Map_Layout->setScene(this->scene_region_map_layout); + this->ui->graphicsView_Region_Map_Layout->setFixedSize(this->region_map->imgSize()); +} + +void Editor::displayRegionMapLayoutOptions() { + // + this->ui->comboBox_RM_ConnectedMap->addItems(*(this->project->regionMapSections)); + + this->ui->frame_RM_Options->setEnabled(true); + + // TODO: change these values to variables + this->ui->spinBox_RM_Options_x->setMaximum(27); + this->ui->spinBox_RM_Options_y->setMaximum(14); + + updateRegionMapLayoutOptions(65); +} + +void Editor::updateRegionMapLayoutOptions(int index) { + // + this->ui->lineEdit_RM_MapName->setText(this->project->mapSecToMapHoverName->value(this->region_map->map_squares[index].mapsec));//this->region_map->map_squares[index].map_name); + this->ui->comboBox_RM_ConnectedMap->setCurrentText(this->region_map->map_squares[index].mapsec); + this->ui->spinBox_RM_Options_x->setValue(this->region_map->map_squares[index].x); + this->ui->spinBox_RM_Options_y->setValue(this->region_map->map_squares[index].y); } void Editor::onRegionMapTileSelectorSelectedTileChanged() { @@ -1330,18 +1415,62 @@ void Editor::onRegionMapTileSelectorHoveredTileChanged(unsigned tileId) { void Editor::onRegionMapTileSelectorHoveredTileCleared() { // - QString message = QString("Selected Tile: 0x") + QString("%1").arg(this->mapsquare_selector_item->selectedTile, 4, 16, QChar('0')).toUpper(); + //QString message = QString("Selected Tile: 0x") + QString("%1").arg(this->region_map_layout_item->selectedTile, 4, 16, QChar('0')).toUpper(); + //this->ui->statusBar->showMessage(message); +} + +void Editor::onRegionMapLayoutSelectedTileChanged(int index) { + // + QString message = QString(); + if (this->region_map->map_squares[index].has_map) { + // + message = QString("Map: %1").arg(this->project->mapSecToMapHoverName->value( + this->region_map->map_squares[index].mapsec)).remove("{NAME_END}");//.remove("{NAME_END}") + } + this->ui->statusBar->showMessage(message); + + updateRegionMapLayoutOptions(index); +} + +void Editor::onRegionMapLayoutHoveredTileChanged(int index) { + // TODO: change to x, y coords not index + QString message = QString(); + int x = this->region_map->map_squares[index].x; + int y = this->region_map->map_squares[index].y; + if (x >= 0 && y >= 0) { + message = QString("(%1, %2)").arg(x).arg(y); + if (this->region_map->map_squares[index].has_map) { + // + message += QString("Map: %1").arg(this->project->mapSecToMapHoverName->value( + this->region_map->map_squares[index].mapsec)).remove("{NAME_END}"); + } + } + this->ui->statusBar->showMessage(message); +} + +void Editor::onRegionMapLayoutHoveredTileCleared() { + // + int index = this->region_map_layout_item->selectedTile; + QString message = QString(); + int x = this->region_map->map_squares[index].x; + int y = this->region_map->map_squares[index].y; + if (x >= 0 && y >= 0) { + message = QString("(%1, %2)").arg(x).arg(y); + if (this->region_map->map_squares[index].has_map) { + // + message += QString("Map: %1").arg(this->project->mapSecToMapHoverName->value( + this->region_map->map_squares[index].mapsec)).remove("{NAME_END}"); + } + } this->ui->statusBar->showMessage(message); } void Editor::onHoveredRegionMapTileChanged(int x, int y) { - // - regionMapTabStatusbarMessage = QString("x: %1, y: %2 Tile: 0x").arg(x).arg(y) + QString("%1").arg(this->region_map->getTileId(x, y), 4, 16, QChar('0')).toUpper(); - this->ui->statusBar->showMessage(regionMapTabStatusbarMessage); + rmStatusbarMessage = QString("x: %1, y: %2 Tile: 0x").arg(x).arg(y) + QString("%1").arg(this->region_map->getTileId(x, y), 4, 16, QChar('0')).toUpper(); + this->ui->statusBar->showMessage(rmStatusbarMessage); } void Editor::onHoveredRegionMapTileCleared() { - // this->ui->statusBar->clearMessage(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0bf6e874..9aebd89a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1986,6 +1986,19 @@ void MainWindow::on_horizontalSlider_MetatileZoom_valueChanged(int value) { ui->graphicsView_Metatiles->setFixedSize(size.width() + 2, size.height() + 2); } +void MainWindow::on_pushButton_RM_Options_save_clicked() { + // + this->editor->region_map->saveOptions( + // + this->editor->region_map_layout_item->selectedTile, + this->ui->comboBox_RM_ConnectedMap->currentText(), + this->ui->lineEdit_RM_MapName->text(), + this->ui->spinBox_RM_Options_x->value(), + this->ui->spinBox_RM_Options_y->value() + ); + this->editor->region_map_layout_item->draw(); +} + void MainWindow::closeEvent(QCloseEvent *event) { porymapConfig.setGeometry( this->saveGeometry(), diff --git a/src/project.cpp b/src/project.cpp index d763efba..d7e99ce3 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1512,6 +1512,7 @@ void Project::readRegionMapSections() { QString filepath = root + "/include/constants/region_map_sections.h"; QStringList prefixes = (QStringList() << "MAPSEC_"); readCDefinesSorted(filepath, prefixes, regionMapSections); + regionMapSections->removeAll("MAPSEC_SUBTRACT_KANTO");// TODO: fix this (in repos?) } void Project::readItemNames() { diff --git a/src/ui/regionmaplayoutpixmapitem.cpp b/src/ui/regionmaplayoutpixmapitem.cpp new file mode 100644 index 00000000..24de0e53 --- /dev/null +++ b/src/ui/regionmaplayoutpixmapitem.cpp @@ -0,0 +1,85 @@ +#include "regionmaplayoutpixmapitem.h" + + + +// TODO: make this connected (by duplicating scene rect maybe?) to background image tab +// +void RegionMapLayoutPixmapItem::draw() { + if (!region_map) return; + + QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888); + + QPainter painter(&image); + for (int i = 0; i < region_map->map_squares.size(); i++) { + QImage bottom_img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id); + QImage top_img(8, 8, QImage::Format_RGBA8888); + if (region_map->map_squares[i].has_map) { + top_img.fill(Qt::gray); + } else { + top_img.fill(Qt::black); + } + int x = i % region_map->width(); + int y = i / region_map->width(); + QPoint pos = QPoint(x * 8, y * 8); + painter.setOpacity(1); + painter.drawImage(pos, bottom_img); + painter.save(); + painter.setOpacity(0.55); + painter.drawImage(pos, top_img); + painter.restore(); + } + painter.end(); + + this->setPixmap(QPixmap::fromImage(image)); + this->drawSelection(); +} + +void RegionMapLayoutPixmapItem::setDefaultSelection() { + this->select(1,2); +} + +void RegionMapLayoutPixmapItem::select(int x, int y) { + int index = this->region_map->getMapSquareIndex(x, y); + SelectablePixmapItem::select(x, y, 0, 0); + this->selectedTile = index; + this->updateSelectedTile(); + + emit selectedTileChanged(index); +} + +void RegionMapLayoutPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QPoint pos = this->getCellPos(event->pos()); + int index = this->region_map->getMapSquareIndex(pos.x(), pos.y()); + if (this->region_map->map_squares[index].x >= 0 + && this->region_map->map_squares[index].y >= 0) { + SelectablePixmapItem::mousePressEvent(event); + this->updateSelectedTile(); + emit selectedTileChanged(this->selectedTile); + } +} + +void RegionMapLayoutPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mouseMoveEvent(event); + this->updateSelectedTile(); + emit hoveredTileChanged(this->selectedTile); + emit selectedTileChanged(this->selectedTile); +} + +void RegionMapLayoutPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + // +} + +void RegionMapLayoutPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + QPoint pos = this->getCellPos(event->pos()); + int tileId = this->region_map->getMapSquareIndex(pos.x(), pos.y()); + emit this->hoveredTileChanged(tileId); +} + +void RegionMapLayoutPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { + emit this->hoveredTileCleared(); +} + +void RegionMapLayoutPixmapItem::updateSelectedTile() { + QPoint origin = this->getSelectionStart(); + this->selectedTile = this->region_map->getMapSquareIndex(origin.x(), origin.y()); +} diff --git a/src/ui/tilemaptileselector.cpp b/src/ui/tilemaptileselector.cpp index b109ceb2..af7dfdc5 100644 --- a/src/ui/tilemaptileselector.cpp +++ b/src/ui/tilemaptileselector.cpp @@ -7,7 +7,7 @@ void TilemapTileSelector::draw() { this->pixelWidth = width_; size_t height_ = this->pixmap.height(); this->pixelHeight = height_; - size_t ntiles_ = (width_/8) * (height_/8);// length_ + size_t ntiles_ = (width_/8) * (height_/8); this->numTilesWide = width_ / 8; this->numTiles = ntiles_; @@ -16,97 +16,63 @@ void TilemapTileSelector::draw() { this->drawSelection(); } -//* void TilemapTileSelector::select(unsigned tileId) { QPoint coords = this->getTileIdCoords(tileId); SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0); this->selectedTile = tileId; emit selectedTileChanged(tileId); } -//*/ -//* void TilemapTileSelector::updateSelectedTile() { QPoint origin = this->getSelectionStart(); this->selectedTile = this->getTileId(origin.x(), origin.y()); } -//*/ unsigned TilemapTileSelector::getSelectedTile() { return this->selectedTile; } -//* unsigned TilemapTileSelector::getTileId(int x, int y) { int index = y * this->numTilesWide + x; return index < this->numTiles ? index : this->numTiles % index; } -//*/ -//* void TilemapTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) { SelectablePixmapItem::mousePressEvent(event); this->updateSelectedTile(); emit selectedTileChanged(this->selectedTile); } -//*/ -//* void TilemapTileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { SelectablePixmapItem::mouseMoveEvent(event); this->updateSelectedTile(); emit hoveredTileChanged(this->selectedTile); emit selectedTileChanged(this->selectedTile); } -//*/ -//* void TilemapTileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { SelectablePixmapItem::mouseReleaseEvent(event); this->updateSelectedTile(); emit selectedTileChanged(this->selectedTile); } -//*/ -//* void TilemapTileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { QPoint pos = this->getCellPos(event->pos()); unsigned tileId = this->getTileId(pos.x(), pos.y()); emit this->hoveredTileChanged(tileId); } -//*/ -//* void TilemapTileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { emit this->hoveredTileCleared(); } -//*/ -//* QPoint TilemapTileSelector::getTileIdCoords(unsigned tileId) { - int index = tileId < this->numTiles ? tileId : this->numTiles % tileId;// TODO: change this? - return QPoint(index % this->numTilesWide, index / this->numTilesWide);// ? is this right? + int index = tileId < this->numTiles ? tileId : this->numTiles % tileId; + return QPoint(index % this->numTilesWide, index / this->numTilesWide); } -//*/ QImage TilemapTileSelector::tileImg(unsigned tileId) { // QPoint pos = getTileIdCoords(tileId); return pixmap.copy(pos.x() * 8, pos.y() * 8, 8, 8).toImage(); } - - - - - - - - - - - - - - - -