2018-09-29 20:13:07 +01:00
# include "tileseteditor.h"
# include "ui_tileseteditor.h"
2018-12-20 23:30:35 +00:00
# include "log.h"
2018-09-30 20:54:38 +01:00
# include "imageproviders.h"
2019-01-09 00:04:41 +00:00
# include "metatileparser.h"
2019-04-06 23:11:56 +01:00
# include "paletteutil.h"
2019-01-11 14:52:47 +00:00
# include "imageexport.h"
2020-03-16 20:31:08 +00:00
# include "config.h"
2020-11-09 10:50:15 +00:00
# include "shortcut.h"
2018-10-03 01:01:24 +01:00
# include <QFileDialog>
# include <QMessageBox>
2018-10-03 01:01:37 +01:00
# include <QDialogButtonBox>
2018-10-08 04:17:20 +01:00
# include <QCloseEvent>
2019-01-07 15:31:48 +00:00
# include <QImageReader>
2018-09-29 20:13:07 +01:00
2020-07-02 02:19:08 +01:00
TilesetEditor : : TilesetEditor ( Project * project , Map * map , QWidget * parent ) :
2018-09-29 20:13:07 +01:00
QMainWindow ( parent ) ,
2020-09-25 13:20:51 +01:00
ui ( new Ui : : TilesetEditor ) ,
project ( project ) ,
map ( map ) ,
hasUnsavedChanges ( false )
2018-09-29 20:13:07 +01:00
{
2020-09-25 13:20:51 +01:00
this - > setTilesets ( this - > map - > layout - > tileset_primary_label , this - > map - > layout - > tileset_secondary_label ) ;
this - > initUi ( ) ;
this - > initMetatileHistory ( ) ;
2018-10-03 01:01:31 +01:00
}
TilesetEditor : : ~ TilesetEditor ( )
{
delete ui ;
2018-12-26 22:49:43 +00:00
delete metatileSelector ;
delete tileSelector ;
delete metatileLayersItem ;
delete paletteEditor ;
delete metatile ;
delete primaryTileset ;
delete secondaryTileset ;
delete metatilesScene ;
delete tilesScene ;
delete selectedTilePixmapItem ;
delete selectedTileScene ;
delete metatileLayersScene ;
2022-03-30 23:03:13 +01:00
delete copiedMetatile ;
2018-10-03 01:01:31 +01:00
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : update ( Map * map , QString primaryTilesetLabel , QString secondaryTilesetLabel ) {
this - > updateMap ( map ) ;
this - > updateTilesets ( primaryTilesetLabel , secondaryTilesetLabel ) ;
}
void TilesetEditor : : updateMap ( Map * map ) {
this - > map = map ;
this - > metatileSelector - > map = map ;
}
2018-09-29 20:13:07 +01:00
2020-09-25 13:20:51 +01:00
void TilesetEditor : : updateTilesets ( QString primaryTilesetLabel , QString secondaryTilesetLabel ) {
if ( this - > hasUnsavedChanges ) {
QMessageBox : : StandardButton result = QMessageBox : : question (
this ,
" porymap " ,
" Tileset has been modified, save changes? " ,
QMessageBox : : No | QMessageBox : : Yes ,
QMessageBox : : Yes ) ;
if ( result = = QMessageBox : : Yes )
this - > on_actionSave_Tileset_triggered ( ) ;
}
2018-10-03 01:01:31 +01:00
this - > hasUnsavedChanges = false ;
2020-09-25 13:20:51 +01:00
this - > setTilesets ( primaryTilesetLabel , secondaryTilesetLabel ) ;
this - > refresh ( ) ;
}
2018-10-03 01:01:15 +01:00
2020-09-25 13:20:51 +01:00
bool TilesetEditor : : selectMetatile ( uint16_t metatileId ) {
if ( ! Tileset : : metatileIsValid ( metatileId , this - > primaryTileset , this - > secondaryTileset ) ) return false ;
this - > metatileSelector - > select ( metatileId ) ;
QPoint pos = this - > metatileSelector - > getMetatileIdCoordsOnWidget ( metatileId ) ;
this - > ui - > scrollArea_Metatiles - > ensureVisible ( pos . x ( ) , pos . y ( ) ) ;
return true ;
}
2022-03-30 23:03:13 +01:00
uint16_t TilesetEditor : : getSelectedMetatileId ( ) {
return this - > metatileSelector - > getSelectedMetatileId ( ) ;
2021-11-23 17:58:04 +00:00
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : setTilesets ( QString primaryTilesetLabel , QString secondaryTilesetLabel ) {
Tileset * primaryTileset = project - > getTileset ( primaryTilesetLabel ) ;
Tileset * secondaryTileset = project - > getTileset ( secondaryTilesetLabel ) ;
2018-10-03 01:01:31 +01:00
if ( this - > primaryTileset ) delete this - > primaryTileset ;
if ( this - > secondaryTileset ) delete this - > secondaryTileset ;
2021-02-17 02:45:54 +00:00
this - > primaryTileset = new Tileset ( * primaryTileset ) ;
this - > secondaryTileset = new Tileset ( * secondaryTileset ) ;
2021-01-16 16:12:38 +00:00
if ( paletteEditor ) paletteEditor - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
2020-09-25 13:20:51 +01:00
}
void TilesetEditor : : initUi ( ) {
ui - > setupUi ( this ) ;
this - > tileXFlip = ui - > checkBox_xFlip - > isChecked ( ) ;
this - > tileYFlip = ui - > checkBox_yFlip - > isChecked ( ) ;
this - > paletteId = ui - > spinBox_paletteSelector - > value ( ) ;
this - > ui - > spinBox_paletteSelector - > setMinimum ( 0 ) ;
this - > ui - > spinBox_paletteSelector - > setMaximum ( Project : : getNumPalettesTotal ( ) - 1 ) ;
this - > setMetatileBehaviors ( ) ;
this - > setMetatileLayersUi ( ) ;
this - > setVersionSpecificUi ( ) ;
this - > setMetatileLabelValidator ( ) ;
this - > initMetatileSelector ( ) ;
this - > initMetatileLayersItem ( ) ;
this - > initTileSelector ( ) ;
this - > initSelectedTileItem ( ) ;
2020-11-09 10:50:15 +00:00
this - > initShortcuts ( ) ;
2020-09-25 13:20:51 +01:00
this - > metatileSelector - > select ( 0 ) ;
this - > restoreWindowState ( ) ;
}
2018-09-29 21:24:35 +01:00
2020-09-25 13:20:51 +01:00
void TilesetEditor : : setMetatileBehaviors ( ) {
2018-10-03 01:01:09 +01:00
for ( int num : project - > metatileBehaviorMapInverse . keys ( ) ) {
this - > ui - > comboBox_metatileBehaviors - > addItem ( project - > metatileBehaviorMapInverse [ num ] , num ) ;
}
2020-09-25 13:20:51 +01:00
}
2020-06-26 03:05:10 +01:00
2020-09-25 13:20:51 +01:00
void TilesetEditor : : setMetatileLayersUi ( ) {
2020-06-26 03:05:10 +01:00
if ( ! projectConfig . getTripleLayerMetatilesEnabled ( ) ) {
2021-11-23 21:11:07 +00:00
this - > ui - > comboBox_layerType - > addItem ( " Normal - Middle/Top " , METATILE_LAYER_MIDDLE_TOP ) ;
this - > ui - > comboBox_layerType - > addItem ( " Covered - Bottom/Middle " , METATILE_LAYER_BOTTOM_MIDDLE ) ;
this - > ui - > comboBox_layerType - > addItem ( " Split - Bottom/Top " , METATILE_LAYER_BOTTOM_TOP ) ;
2020-06-26 03:05:10 +01:00
} else {
this - > ui - > comboBox_layerType - > setVisible ( false ) ;
this - > ui - > label_layerType - > setVisible ( false ) ;
2020-06-26 03:14:58 +01:00
this - > ui - > label_BottomTop - > setText ( " Bottom/Middle/Top " ) ;
2020-06-26 03:05:10 +01:00
}
2020-09-25 13:20:51 +01:00
}
2020-06-26 03:05:10 +01:00
2020-09-25 13:20:51 +01:00
void TilesetEditor : : setVersionSpecificUi ( ) {
2020-03-16 20:31:08 +00:00
if ( projectConfig . getBaseGameVersion ( ) = = BaseGameVersion : : pokefirered ) {
this - > ui - > comboBox_encounterType - > setVisible ( true ) ;
this - > ui - > label_encounterType - > setVisible ( true ) ;
2021-11-23 21:11:07 +00:00
this - > ui - > comboBox_encounterType - > addItem ( " None " , ENCOUNTER_NONE ) ;
this - > ui - > comboBox_encounterType - > addItem ( " Land " , ENCOUNTER_LAND ) ;
this - > ui - > comboBox_encounterType - > addItem ( " Water " , ENCOUNTER_WATER ) ;
2020-03-16 20:31:08 +00:00
this - > ui - > comboBox_terrainType - > setVisible ( true ) ;
this - > ui - > label_terrainType - > setVisible ( true ) ;
2021-11-23 21:11:07 +00:00
this - > ui - > comboBox_terrainType - > addItem ( " Normal " , TERRAIN_NONE ) ;
this - > ui - > comboBox_terrainType - > addItem ( " Grass " , TERRAIN_GRASS ) ;
this - > ui - > comboBox_terrainType - > addItem ( " Water " , TERRAIN_WATER ) ;
this - > ui - > comboBox_terrainType - > addItem ( " Waterfall " , TERRAIN_WATERFALL ) ;
2020-03-16 20:31:08 +00:00
} else {
this - > ui - > comboBox_encounterType - > setVisible ( false ) ;
this - > ui - > label_encounterType - > setVisible ( false ) ;
this - > ui - > comboBox_terrainType - > setVisible ( false ) ;
this - > ui - > label_terrainType - > setVisible ( false ) ;
}
2020-09-25 13:20:51 +01:00
}
2020-03-16 20:31:08 +00:00
2020-09-25 13:20:51 +01:00
void TilesetEditor : : setMetatileLabelValidator ( ) {
2019-04-04 06:44:31 +01:00
//only allow characters valid for a symbol
2021-02-06 00:43:49 +00:00
QRegularExpression expression ( " [_A-Za-z0-9]*$ " ) ;
QRegularExpressionValidator * validator = new QRegularExpressionValidator ( expression ) ;
2019-04-04 06:44:31 +01:00
this - > ui - > lineEdit_metatileLabel - > setValidator ( validator ) ;
2020-09-25 13:12:13 +01:00
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : initMetatileSelector ( )
2018-09-29 20:13:07 +01:00
{
2020-09-25 13:20:51 +01:00
this - > metatileSelector = new TilesetEditorMetatileSelector ( this - > primaryTileset , this - > secondaryTileset , this - > map ) ;
2021-02-14 15:07:55 +00:00
connect ( this - > metatileSelector , & TilesetEditorMetatileSelector : : hoveredMetatileChanged ,
this , & TilesetEditor : : onHoveredMetatileChanged ) ;
connect ( this - > metatileSelector , & TilesetEditorMetatileSelector : : hoveredMetatileCleared ,
this , & TilesetEditor : : onHoveredMetatileCleared ) ;
connect ( this - > metatileSelector , & TilesetEditorMetatileSelector : : selectedMetatileChanged ,
this , & TilesetEditor : : onSelectedMetatileChanged ) ;
2018-09-29 21:24:35 +01:00
this - > metatilesScene = new QGraphicsScene ;
this - > metatilesScene - > addItem ( this - > metatileSelector ) ;
this - > metatileSelector - > draw ( ) ;
this - > ui - > graphicsView_Metatiles - > setScene ( this - > metatilesScene ) ;
this - > ui - > graphicsView_Metatiles - > setFixedSize ( this - > metatileSelector - > pixmap ( ) . width ( ) + 2 , this - > metatileSelector - > pixmap ( ) . height ( ) + 2 ) ;
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : initMetatileLayersItem ( ) {
2022-03-30 23:03:13 +01:00
Metatile * metatile = Tileset : : getMetatile ( this - > getSelectedMetatileId ( ) , this - > primaryTileset , this - > secondaryTileset ) ;
2020-09-25 13:20:51 +01:00
this - > metatileLayersItem = new MetatileLayersItem ( metatile , this - > primaryTileset , this - > secondaryTileset ) ;
2021-02-14 15:07:55 +00:00
connect ( this - > metatileLayersItem , & MetatileLayersItem : : tileChanged ,
this , & TilesetEditor : : onMetatileLayerTileChanged ) ;
connect ( this - > metatileLayersItem , & MetatileLayersItem : : selectedTilesChanged ,
this , & TilesetEditor : : onMetatileLayerSelectionChanged ) ;
2020-09-25 13:20:51 +01:00
this - > metatileLayersScene = new QGraphicsScene ;
this - > metatileLayersScene - > addItem ( this - > metatileLayersItem ) ;
this - > ui - > graphicsView_metatileLayers - > setScene ( this - > metatileLayersScene ) ;
}
2018-09-30 18:33:58 +01:00
void TilesetEditor : : initTileSelector ( )
{
2021-02-14 15:07:55 +00:00
this - > tileSelector = new TilesetEditorTileSelector ( this - > primaryTileset , this - > secondaryTileset ,
projectConfig . getTripleLayerMetatilesEnabled ( ) ) ;
connect ( this - > tileSelector , & TilesetEditorTileSelector : : hoveredTileChanged ,
this , & TilesetEditor : : onHoveredTileChanged ) ;
connect ( this - > tileSelector , & TilesetEditorTileSelector : : hoveredTileCleared ,
this , & TilesetEditor : : onHoveredTileCleared ) ;
connect ( this - > tileSelector , & TilesetEditorTileSelector : : selectedTilesChanged ,
this , & TilesetEditor : : onSelectedTilesChanged ) ;
2018-09-30 18:33:58 +01:00
this - > tilesScene = new QGraphicsScene ;
this - > tilesScene - > addItem ( this - > tileSelector ) ;
this - > tileSelector - > select ( 0 ) ;
this - > tileSelector - > draw ( ) ;
this - > ui - > graphicsView_Tiles - > setScene ( this - > tilesScene ) ;
this - > ui - > graphicsView_Tiles - > setFixedSize ( this - > tileSelector - > pixmap ( ) . width ( ) + 2 , this - > tileSelector - > pixmap ( ) . height ( ) + 2 ) ;
}
2018-09-30 20:54:38 +01:00
void TilesetEditor : : initSelectedTileItem ( ) {
this - > selectedTileScene = new QGraphicsScene ;
2018-10-03 01:01:27 +01:00
this - > drawSelectedTiles ( ) ;
2018-09-30 20:54:38 +01:00
this - > ui - > graphicsView_selectedTile - > setScene ( this - > selectedTileScene ) ;
2018-10-08 20:42:51 +01:00
this - > ui - > graphicsView_selectedTile - > setFixedSize ( this - > selectedTilePixmapItem - > pixmap ( ) . width ( ) + 2 , this - > selectedTilePixmapItem - > pixmap ( ) . height ( ) + 2 ) ;
2018-09-30 20:54:38 +01:00
}
2020-11-09 10:50:15 +00:00
void TilesetEditor : : initShortcuts ( ) {
2020-11-13 04:48:03 +00:00
initExtraShortcuts ( ) ;
2020-11-09 10:50:15 +00:00
shortcutsConfig . load ( ) ;
shortcutsConfig . setDefaultShortcuts ( shortcutableObjects ( ) ) ;
applyUserShortcuts ( ) ;
}
2020-11-13 04:48:03 +00:00
void TilesetEditor : : initExtraShortcuts ( ) {
ui - > actionRedo - > setShortcuts ( { ui - > actionRedo - > shortcut ( ) , QKeySequence ( " Ctrl+Shift+Z " ) } ) ;
auto * shortcut_xFlip = new Shortcut ( QKeySequence ( ) , ui - > checkBox_xFlip , SLOT ( toggle ( ) ) ) ;
shortcut_xFlip - > setObjectName ( " shortcut_xFlip " ) ;
shortcut_xFlip - > setWhatsThis ( " X Flip " ) ;
auto * shortcut_yFlip = new Shortcut ( QKeySequence ( ) , ui - > checkBox_yFlip , SLOT ( toggle ( ) ) ) ;
shortcut_yFlip - > setObjectName ( " shortcut_yFlip " ) ;
shortcut_yFlip - > setWhatsThis ( " Y Flip " ) ;
}
2020-11-09 10:50:15 +00:00
QObjectList TilesetEditor : : shortcutableObjects ( ) const {
QObjectList shortcutable_objects ;
2020-11-13 04:48:03 +00:00
2020-11-09 10:50:15 +00:00
for ( auto * action : findChildren < QAction * > ( ) )
2020-11-13 04:48:03 +00:00
if ( ! action - > objectName ( ) . isEmpty ( ) )
2020-11-09 10:50:15 +00:00
shortcutable_objects . append ( qobject_cast < QObject * > ( action ) ) ;
for ( auto * shortcut : findChildren < Shortcut * > ( ) )
2020-11-13 04:48:03 +00:00
if ( ! shortcut - > objectName ( ) . isEmpty ( ) )
2020-11-09 10:50:15 +00:00
shortcutable_objects . append ( qobject_cast < QObject * > ( shortcut ) ) ;
2020-11-13 04:48:03 +00:00
2020-11-09 10:50:15 +00:00
return shortcutable_objects ;
}
void TilesetEditor : : applyUserShortcuts ( ) {
for ( auto * action : findChildren < QAction * > ( ) )
2020-11-13 04:48:03 +00:00
if ( ! action - > objectName ( ) . isEmpty ( ) )
2020-11-09 10:50:15 +00:00
action - > setShortcuts ( shortcutsConfig . userShortcuts ( action ) ) ;
for ( auto * shortcut : findChildren < Shortcut * > ( ) )
2020-11-13 04:48:03 +00:00
if ( ! shortcut - > objectName ( ) . isEmpty ( ) )
2020-11-09 10:50:15 +00:00
shortcut - > setKeys ( shortcutsConfig . userShortcuts ( shortcut ) ) ;
}
2020-09-25 13:12:13 +01:00
void TilesetEditor : : restoreWindowState ( ) {
logInfo ( " Restoring tileset editor geometry from previous session. " ) ;
QMap < QString , QByteArray > geometry = porymapConfig . getTilesetEditorGeometry ( ) ;
this - > restoreGeometry ( geometry . value ( " tileset_editor_geometry " ) ) ;
this - > restoreState ( geometry . value ( " tileset_editor_state " ) ) ;
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : initMetatileHistory ( ) {
2021-02-16 18:22:41 +00:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( 0 , nullptr , new Metatile ( * metatile ) ) ;
2020-09-25 13:20:51 +01:00
metatileHistory . push ( commit ) ;
}
2020-09-25 13:12:13 +01:00
void TilesetEditor : : reset ( ) {
this - > hasUnsavedChanges = false ;
this - > setTilesets ( this - > primaryTileset - > name , this - > secondaryTileset - > name ) ;
if ( this - > paletteEditor )
this - > paletteEditor - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
this - > refresh ( ) ;
}
2020-09-25 13:20:51 +01:00
void TilesetEditor : : refresh ( ) {
this - > metatileLayersItem - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
this - > tileSelector - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
this - > metatileSelector - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
2022-03-30 23:03:13 +01:00
this - > metatileSelector - > select ( this - > getSelectedMetatileId ( ) ) ;
2020-09-25 13:20:51 +01:00
this - > drawSelectedTiles ( ) ;
2021-07-20 03:02:31 +01:00
if ( metatileSelector ) {
if ( metatileSelector - > selectorShowUnused | | metatileSelector - > selectorShowCounts ) {
countMetatileUsage ( ) ;
this - > metatileSelector - > draw ( ) ;
}
}
2021-07-21 23:55:33 +01:00
if ( tileSelector ) {
if ( tileSelector - > showUnused ) {
countTileUsage ( ) ;
this - > tileSelector - > draw ( ) ;
}
}
2020-09-25 13:20:51 +01:00
this - > ui - > graphicsView_Tiles - > setSceneRect ( 0 , 0 , this - > tileSelector - > pixmap ( ) . width ( ) + 2 , this - > tileSelector - > pixmap ( ) . height ( ) + 2 ) ;
this - > ui - > graphicsView_Tiles - > setFixedSize ( this - > tileSelector - > pixmap ( ) . width ( ) + 2 , this - > tileSelector - > pixmap ( ) . height ( ) + 2 ) ;
this - > ui - > graphicsView_Metatiles - > setSceneRect ( 0 , 0 , this - > metatileSelector - > pixmap ( ) . width ( ) + 2 , this - > metatileSelector - > pixmap ( ) . height ( ) + 2 ) ;
this - > ui - > graphicsView_Metatiles - > setFixedSize ( this - > metatileSelector - > pixmap ( ) . width ( ) + 2 , this - > metatileSelector - > pixmap ( ) . height ( ) + 2 ) ;
this - > ui - > graphicsView_selectedTile - > setFixedSize ( this - > selectedTilePixmapItem - > pixmap ( ) . width ( ) + 2 , this - > selectedTilePixmapItem - > pixmap ( ) . height ( ) + 2 ) ;
}
2018-10-03 01:01:27 +01:00
void TilesetEditor : : drawSelectedTiles ( ) {
2018-09-30 20:54:38 +01:00
if ( ! this - > selectedTileScene ) {
return ;
}
2018-09-30 22:15:04 +01:00
this - > selectedTileScene - > clear ( ) ;
2018-10-06 21:49:26 +01:00
QList < Tile > tiles = this - > tileSelector - > getSelectedTiles ( ) ;
2018-10-03 01:01:27 +01:00
QPoint dimensions = this - > tileSelector - > getSelectionDimensions ( ) ;
2018-10-03 01:01:34 +01:00
QImage selectionImage ( 16 * dimensions . x ( ) , 16 * dimensions . y ( ) , QImage : : Format_RGBA8888 ) ;
2018-10-03 01:01:27 +01:00
QPainter painter ( & selectionImage ) ;
int tileIndex = 0 ;
for ( int j = 0 ; j < dimensions . y ( ) ; j + + ) {
for ( int i = 0 ; i < dimensions . x ( ) ; i + + ) {
2021-11-24 04:53:41 +00:00
QImage tileImage = getPalettedTileImage ( tiles . at ( tileIndex ) . tileId , this - > primaryTileset , this - > secondaryTileset , tiles . at ( tileIndex ) . palette , true )
2018-10-06 21:49:26 +01:00
. mirrored ( tiles . at ( tileIndex ) . xflip , tiles . at ( tileIndex ) . yflip )
2018-10-03 01:01:34 +01:00
. scaled ( 16 , 16 ) ;
2018-10-03 01:01:27 +01:00
tileIndex + + ;
2018-10-03 01:01:34 +01:00
painter . drawImage ( i * 16 , j * 16 , tileImage ) ;
2018-10-03 01:01:27 +01:00
}
}
this - > selectedTilePixmapItem = new QGraphicsPixmapItem ( QPixmap : : fromImage ( selectionImage ) ) ;
2018-09-30 20:54:38 +01:00
this - > selectedTileScene - > addItem ( this - > selectedTilePixmapItem ) ;
2018-10-08 20:42:51 +01:00
this - > ui - > graphicsView_selectedTile - > setFixedSize ( this - > selectedTilePixmapItem - > pixmap ( ) . width ( ) + 2 , this - > selectedTilePixmapItem - > pixmap ( ) . height ( ) + 2 ) ;
2018-09-30 20:54:38 +01:00
}
2018-09-29 21:24:35 +01:00
void TilesetEditor : : onHoveredMetatileChanged ( uint16_t metatileId ) {
2019-04-04 06:44:31 +01:00
Metatile * metatile = Tileset : : getMetatile ( metatileId , this - > primaryTileset , this - > secondaryTileset ) ;
QString message ;
QString hexString = QString ( " %1 " ) . arg ( metatileId , 3 , 16 , QChar ( ' 0 ' ) ) . toUpper ( ) ;
if ( metatile & & metatile - > label . size ( ) ! = 0 ) {
message = QString ( " Metatile: 0x%1 \" %2 \" " ) . arg ( hexString , metatile - > label ) ;
} else {
message = QString ( " Metatile: 0x%1 " ) . arg ( hexString ) ;
}
2018-09-29 21:24:35 +01:00
this - > ui - > statusbar - > showMessage ( message ) ;
}
void TilesetEditor : : onHoveredMetatileCleared ( ) {
this - > ui - > statusbar - > clearMessage ( ) ;
}
2018-09-30 22:15:04 +01:00
void TilesetEditor : : onSelectedMetatileChanged ( uint16_t metatileId ) {
2018-10-03 01:01:15 +01:00
this - > metatile = Tileset : : getMetatile ( metatileId , this - > primaryTileset , this - > secondaryTileset ) ;
2018-09-30 22:15:04 +01:00
this - > metatileLayersItem - > setMetatile ( metatile ) ;
this - > metatileLayersItem - > draw ( ) ;
2020-06-25 06:32:42 +01:00
this - > ui - > graphicsView_metatileLayers - > setFixedSize ( this - > metatileLayersItem - > pixmap ( ) . width ( ) + 2 , this - > metatileLayersItem - > pixmap ( ) . height ( ) + 2 ) ;
2018-10-03 01:01:09 +01:00
this - > ui - > comboBox_metatileBehaviors - > setCurrentIndex ( this - > ui - > comboBox_metatileBehaviors - > findData ( this - > metatile - > behavior ) ) ;
2019-04-04 06:44:31 +01:00
this - > ui - > lineEdit_metatileLabel - > setText ( this - > metatile - > label ) ;
2020-06-26 03:05:10 +01:00
if ( ! projectConfig . getTripleLayerMetatilesEnabled ( ) ) {
this - > ui - > comboBox_layerType - > setCurrentIndex ( this - > ui - > comboBox_layerType - > findData ( this - > metatile - > layerType ) ) ;
}
2020-03-16 20:31:08 +00:00
if ( projectConfig . getBaseGameVersion ( ) = = BaseGameVersion : : pokefirered ) {
this - > ui - > comboBox_encounterType - > setCurrentIndex ( this - > ui - > comboBox_encounterType - > findData ( this - > metatile - > encounterType ) ) ;
this - > ui - > comboBox_terrainType - > setCurrentIndex ( this - > ui - > comboBox_terrainType - > findData ( this - > metatile - > terrainType ) ) ;
}
2018-09-29 20:13:07 +01:00
}
2018-09-30 18:33:58 +01:00
void TilesetEditor : : onHoveredTileChanged ( uint16_t tile ) {
QString message = QString ( " Tile: 0x%1 " )
. arg ( QString ( " %1 " ) . arg ( tile , 3 , 16 , QChar ( ' 0 ' ) ) . toUpper ( ) ) ;
this - > ui - > statusbar - > showMessage ( message ) ;
}
void TilesetEditor : : onHoveredTileCleared ( ) {
this - > ui - > statusbar - > clearMessage ( ) ;
}
2018-10-03 01:01:27 +01:00
void TilesetEditor : : onSelectedTilesChanged ( ) {
this - > drawSelectedTiles ( ) ;
}
void TilesetEditor : : onMetatileLayerTileChanged ( int x , int y ) {
2021-02-16 17:14:27 +00:00
static const QList < QPoint > tileCoords = QList < QPoint > {
2019-05-23 01:04:25 +01:00
QPoint ( 0 , 0 ) ,
QPoint ( 1 , 0 ) ,
QPoint ( 0 , 1 ) ,
QPoint ( 1 , 1 ) ,
QPoint ( 2 , 0 ) ,
QPoint ( 3 , 0 ) ,
QPoint ( 2 , 1 ) ,
2020-06-25 06:32:42 +01:00
QPoint ( 3 , 1 ) ,
QPoint ( 4 , 0 ) ,
QPoint ( 5 , 0 ) ,
QPoint ( 4 , 1 ) ,
QPoint ( 5 , 1 ) ,
2019-05-23 01:04:25 +01:00
} ;
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2018-10-03 01:01:27 +01:00
QPoint dimensions = this - > tileSelector - > getSelectionDimensions ( ) ;
2018-10-06 21:49:26 +01:00
QList < Tile > tiles = this - > tileSelector - > getSelectedTiles ( ) ;
2018-10-03 01:01:27 +01:00
int selectedTileIndex = 0 ;
2020-06-25 06:32:42 +01:00
bool isTripleLayerMetatile = projectConfig . getTripleLayerMetatilesEnabled ( ) ;
int maxTileIndex = isTripleLayerMetatile ? 12 : 8 ;
2018-10-03 01:01:27 +01:00
for ( int j = 0 ; j < dimensions . y ( ) ; j + + ) {
for ( int i = 0 ; i < dimensions . x ( ) ; i + + ) {
int tileIndex = ( ( x + i ) / 2 * 4 ) + ( ( y + j ) * 2 ) + ( ( x + i ) % 2 ) ;
2020-06-25 06:32:42 +01:00
if ( tileIndex < maxTileIndex
2019-05-23 01:04:25 +01:00
& & tileCoords . at ( tileIndex ) . x ( ) > = x
& & tileCoords . at ( tileIndex ) . y ( ) > = y ) {
2021-02-16 17:14:27 +00:00
Tile & tile = this - > metatile - > tiles [ tileIndex ] ;
2021-11-24 04:53:41 +00:00
tile . tileId = tiles . at ( selectedTileIndex ) . tileId ;
2021-02-16 17:14:27 +00:00
tile . xflip = tiles . at ( selectedTileIndex ) . xflip ;
tile . yflip = tiles . at ( selectedTileIndex ) . yflip ;
tile . palette = tiles . at ( selectedTileIndex ) . palette ;
2018-10-09 23:31:12 +01:00
}
2018-10-03 01:01:27 +01:00
selectedTileIndex + + ;
}
}
2018-09-30 18:33:58 +01:00
2018-09-30 22:15:04 +01:00
this - > metatileSelector - > draw ( ) ;
this - > metatileLayersItem - > draw ( ) ;
2018-10-03 01:01:31 +01:00
this - > hasUnsavedChanges = true ;
2018-10-06 23:07:36 +01:00
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2018-10-06 23:07:36 +01:00
metatileHistory . push ( commit ) ;
2018-09-30 22:15:04 +01:00
}
2018-10-06 21:49:26 +01:00
void TilesetEditor : : onMetatileLayerSelectionChanged ( QPoint selectionOrigin , int width , int height ) {
QList < Tile > tiles ;
2020-07-14 21:27:10 +01:00
QList < int > tileIdxs ;
2018-10-06 21:49:26 +01:00
int x = selectionOrigin . x ( ) ;
int y = selectionOrigin . y ( ) ;
2020-06-25 06:32:42 +01:00
bool isTripleLayerMetatile = projectConfig . getTripleLayerMetatilesEnabled ( ) ;
int maxTileIndex = isTripleLayerMetatile ? 12 : 8 ;
2018-10-06 21:49:26 +01:00
for ( int j = 0 ; j < height ; j + + ) {
for ( int i = 0 ; i < width ; i + + ) {
int tileIndex = ( ( x + i ) / 2 * 4 ) + ( ( y + j ) * 2 ) + ( ( x + i ) % 2 ) ;
2020-06-25 06:32:42 +01:00
if ( tileIndex < maxTileIndex ) {
2021-02-16 17:14:27 +00:00
tiles . append ( this - > metatile - > tiles . at ( tileIndex ) ) ;
2020-07-14 21:27:10 +01:00
tileIdxs . append ( tileIndex ) ;
2018-10-06 21:49:26 +01:00
}
}
}
2018-10-08 20:42:51 +01:00
2020-07-20 16:11:38 +01:00
if ( width = = 1 & & height = = 1 ) {
2021-11-24 04:53:41 +00:00
this - > tileSelector - > highlight ( static_cast < uint16_t > ( tiles [ 0 ] . tileId ) ) ;
2018-10-08 20:42:51 +01:00
ui - > spinBox_paletteSelector - > setValue ( tiles [ 0 ] . palette ) ;
2021-11-24 04:53:41 +00:00
QPoint pos = tileSelector - > getTileCoordsOnWidget ( static_cast < uint16_t > ( tiles [ 0 ] . tileId ) ) ;
2020-07-20 16:11:38 +01:00
ui - > scrollArea_Tiles - > ensureVisible ( pos . x ( ) , pos . y ( ) ) ;
}
2020-07-14 21:27:10 +01:00
this - > tileSelector - > setExternalSelection ( width , height , tiles , tileIdxs ) ;
2018-10-06 23:07:36 +01:00
this - > metatileLayersItem - > clearLastModifiedCoords ( ) ;
2018-10-06 21:49:26 +01:00
}
2018-09-30 20:54:38 +01:00
void TilesetEditor : : on_spinBox_paletteSelector_valueChanged ( int paletteId )
{
2018-10-03 01:01:41 +01:00
this - > ui - > spinBox_paletteSelector - > blockSignals ( true ) ;
this - > ui - > spinBox_paletteSelector - > setValue ( paletteId ) ;
this - > ui - > spinBox_paletteSelector - > blockSignals ( false ) ;
2018-09-30 20:54:38 +01:00
this - > paletteId = paletteId ;
this - > tileSelector - > setPaletteId ( paletteId ) ;
2018-10-03 01:01:27 +01:00
this - > drawSelectedTiles ( ) ;
2018-10-03 01:01:41 +01:00
if ( this - > paletteEditor ) {
this - > paletteEditor - > setPaletteId ( paletteId ) ;
}
2018-10-06 23:07:36 +01:00
this - > metatileLayersItem - > clearLastModifiedCoords ( ) ;
2018-09-30 20:54:38 +01:00
}
void TilesetEditor : : on_checkBox_xFlip_stateChanged ( int checked )
{
this - > tileXFlip = checked ;
2018-10-03 01:01:27 +01:00
this - > tileSelector - > setTileFlips ( this - > tileXFlip , this - > tileYFlip ) ;
this - > drawSelectedTiles ( ) ;
2018-10-06 23:07:36 +01:00
this - > metatileLayersItem - > clearLastModifiedCoords ( ) ;
2018-09-30 20:54:38 +01:00
}
void TilesetEditor : : on_checkBox_yFlip_stateChanged ( int checked )
{
this - > tileYFlip = checked ;
2018-10-03 01:01:27 +01:00
this - > tileSelector - > setTileFlips ( this - > tileXFlip , this - > tileYFlip ) ;
this - > drawSelectedTiles ( ) ;
2018-10-06 23:07:36 +01:00
this - > metatileLayersItem - > clearLastModifiedCoords ( ) ;
2018-09-30 18:33:58 +01:00
}
2018-10-03 01:01:09 +01:00
2021-02-06 00:43:49 +00:00
void TilesetEditor : : on_comboBox_metatileBehaviors_textActivated ( const QString & metatileBehavior )
2018-10-03 01:01:09 +01:00
{
if ( this - > metatile ) {
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2021-11-23 21:11:07 +00:00
this - > metatile - > behavior = static_cast < uint16_t > ( project - > metatileBehaviorMap [ metatileBehavior ] ) ;
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2018-10-06 23:07:36 +01:00
metatileHistory . push ( commit ) ;
2020-07-01 22:18:27 +01:00
this - > hasUnsavedChanges = true ;
2018-10-03 01:01:09 +01:00
}
}
2021-11-23 17:58:04 +00:00
void TilesetEditor : : setMetatileLabel ( QString label )
{
this - > ui - > lineEdit_metatileLabel - > setText ( label ) ;
saveMetatileLabel ( ) ;
}
2019-04-04 06:44:31 +01:00
void TilesetEditor : : on_lineEdit_metatileLabel_editingFinished ( )
2019-04-08 05:13:55 +01:00
{
saveMetatileLabel ( ) ;
}
void TilesetEditor : : saveMetatileLabel ( )
2019-04-04 06:44:31 +01:00
{
2019-04-08 05:17:30 +01:00
// Only commit if the field has changed.
if ( this - > metatile & & this - > metatile - > label ! = this - > ui - > lineEdit_metatileLabel - > text ( ) ) {
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2019-04-04 06:44:31 +01:00
this - > metatile - > label = this - > ui - > lineEdit_metatileLabel - > text ( ) ;
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2019-04-04 06:44:31 +01:00
metatileHistory . push ( commit ) ;
2020-07-01 22:18:27 +01:00
this - > hasUnsavedChanges = true ;
2019-04-04 06:44:31 +01:00
}
}
2018-10-06 23:07:36 +01:00
void TilesetEditor : : on_comboBox_layerType_activated ( int layerType )
2018-10-03 01:01:09 +01:00
{
if ( this - > metatile ) {
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2018-10-03 01:01:09 +01:00
this - > metatile - > layerType = static_cast < uint8_t > ( layerType ) ;
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2018-10-06 23:07:36 +01:00
metatileHistory . push ( commit ) ;
2020-07-01 22:18:27 +01:00
this - > hasUnsavedChanges = true ;
2018-10-03 01:01:09 +01:00
}
}
2020-03-16 20:31:08 +00:00
void TilesetEditor : : on_comboBox_encounterType_activated ( int encounterType )
{
if ( this - > metatile ) {
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2020-03-16 20:31:08 +00:00
this - > metatile - > encounterType = static_cast < uint8_t > ( encounterType ) ;
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2020-03-16 20:31:08 +00:00
metatileHistory . push ( commit ) ;
2020-07-01 22:18:27 +01:00
this - > hasUnsavedChanges = true ;
2020-03-16 20:31:08 +00:00
}
}
void TilesetEditor : : on_comboBox_terrainType_activated ( int terrainType )
{
if ( this - > metatile ) {
2021-02-16 18:22:41 +00:00
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
2020-03-16 20:31:08 +00:00
this - > metatile - > terrainType = static_cast < uint8_t > ( terrainType ) ;
2022-03-30 23:03:13 +01:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( this - > getSelectedMetatileId ( ) ,
2021-02-16 18:22:41 +00:00
prevMetatile , new Metatile ( * this - > metatile ) ) ;
2020-03-16 20:31:08 +00:00
metatileHistory . push ( commit ) ;
2020-07-01 22:18:27 +01:00
this - > hasUnsavedChanges = true ;
2020-03-16 20:31:08 +00:00
}
}
2018-10-03 01:01:09 +01:00
void TilesetEditor : : on_actionSave_Tileset_triggered ( )
{
2019-04-08 05:17:30 +01:00
saveMetatileLabel ( ) ;
2019-04-08 05:13:55 +01:00
2018-10-03 01:01:15 +01:00
this - > project - > saveTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
emit this - > tilesetsSaved ( this - > primaryTileset - > name , this - > secondaryTileset - > name ) ;
2019-01-07 15:12:01 +00:00
if ( this - > paletteEditor ) {
this - > paletteEditor - > setTilesets ( this - > primaryTileset , this - > secondaryTileset ) ;
}
2018-10-03 01:01:21 +01:00
this - > ui - > statusbar - > showMessage ( QString ( " Saved primary and secondary Tilesets! " ) , 5000 ) ;
2018-10-03 01:01:31 +01:00
this - > hasUnsavedChanges = false ;
2018-10-03 01:01:09 +01:00
}
2018-10-03 01:01:24 +01:00
void TilesetEditor : : on_actionImport_Primary_Tiles_triggered ( )
{
this - > importTilesetTiles ( this - > primaryTileset , true ) ;
}
void TilesetEditor : : on_actionImport_Secondary_Tiles_triggered ( )
{
this - > importTilesetTiles ( this - > secondaryTileset , false ) ;
}
void TilesetEditor : : importTilesetTiles ( Tileset * tileset , bool primary ) {
QString descriptor = primary ? " primary " : " secondary " ;
QString descriptorCaps = primary ? " Primary " : " Secondary " ;
QString filepath = QFileDialog : : getOpenFileName (
this ,
QString ( " Import %1 Tileset Tiles Image " ) . arg ( descriptorCaps ) ,
this - > project - > root ,
2019-01-07 15:12:01 +00:00
" Image Files (*.png *.bmp *.jpg *.dib) " ) ;
2018-10-03 01:01:24 +01:00
if ( filepath . isEmpty ( ) ) {
return ;
}
2018-12-20 23:30:35 +00:00
logInfo ( QString ( " Importing %1 tileset tiles '%2' " ) . arg ( descriptor ) . arg ( filepath ) ) ;
2018-10-03 01:01:24 +01:00
2019-01-07 15:31:48 +00:00
// Read image data from buffer so that the built-in QImage doesn't try to detect file format
// purely from the extension name. Advance Map exports ".png" files that are actually BMP format, for example.
QFile file ( filepath ) ;
QImage image ;
if ( file . open ( QIODevice : : ReadOnly ) ) {
QByteArray imageData = file . readAll ( ) ;
image = QImage : : fromData ( imageData ) ;
} else {
logError ( QString ( " Failed to open image file: '%1' " ) . arg ( filepath ) ) ;
}
2018-10-03 01:01:24 +01:00
if ( image . width ( ) = = 0 | | image . height ( ) = = 0 | | image . width ( ) % 8 ! = 0 | | image . height ( ) % 8 ! = 0 ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import tiles. " ) ;
msgBox . setInformativeText ( QString ( " The image dimensions (%1 x %2) are invalid. Width and height must be multiples of 8 pixels. " )
. arg ( image . width ( ) )
. arg ( image . height ( ) ) ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
}
// Validate total number of tiles in image.
2019-01-05 21:52:55 +00:00
int numTilesWide = image . width ( ) / 8 ;
int numTilesHigh = image . height ( ) / 8 ;
2018-10-03 01:01:24 +01:00
int totalTiles = numTilesHigh * numTilesWide ;
int maxAllowedTiles = primary ? Project : : getNumTilesPrimary ( ) : Project : : getNumTilesTotal ( ) - Project : : getNumTilesPrimary ( ) ;
if ( totalTiles > maxAllowedTiles ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import tiles. " ) ;
msgBox . setInformativeText ( QString ( " The maximum number of tiles allowed in the %1 tileset is %2, but the provided image contains %3 total tiles. " )
. arg ( descriptor )
. arg ( maxAllowedTiles )
. arg ( totalTiles ) ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
2019-01-07 15:12:01 +00:00
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
}
// Ask user to provide a palette for the un-indexed image.
if ( image . colorCount ( ) = = 0 ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Select Palette for Tiles " ) ;
2020-10-05 02:47:32 +01:00
msgBox . setInformativeText ( QString ( " The provided image is not indexed. Please select a palette file for the image. An indexed image will be generated using the provided image and palette. " )
2019-01-07 15:12:01 +00:00
. arg ( image . colorCount ( ) ) ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
msgBox . setIcon ( QMessageBox : : Icon : : Warning ) ;
msgBox . exec ( ) ;
QString filepath = QFileDialog : : getOpenFileName (
this ,
QString ( " Select Palette for Tiles Image " ) . arg ( descriptorCaps ) ,
this - > project - > root ,
" Palette Files (*.pal *.act *tpl *gpl) " ) ;
if ( filepath . isEmpty ( ) ) {
return ;
}
bool error = false ;
2021-02-18 08:25:26 +00:00
QList < QRgb > palette = PaletteUtil : : parse ( filepath , & error ) ;
2019-01-07 15:12:01 +00:00
if ( error ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import palette. " ) ;
QString message = QString ( " The palette file could not be processed. View porymap.log for specific errors. " ) ;
msgBox . setInformativeText ( message ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
} else if ( palette . length ( ) ! = 16 ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import palette. " ) ;
QString message = QString ( " The palette must have exactly 16 colors, but it has %1. " ) . arg ( palette . length ( ) ) ;
msgBox . setInformativeText ( message ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
}
QVector < QRgb > colorTable = palette . toVector ( ) ;
image = image . convertToFormat ( QImage : : Format : : Format_Indexed8 , colorTable ) ;
}
// Validate image is properly indexed to 16 colors.
if ( image . colorCount ( ) ! = 16 ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import tiles. " ) ;
msgBox . setInformativeText ( QString ( " The image must be indexed and contain 16 total colors, or it must be un-indexed. The provided image has %1 indexed colors. " )
. arg ( image . colorCount ( ) ) ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
2018-10-03 01:01:24 +01:00
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
}
this - > project - > loadTilesetTiles ( tileset , image ) ;
this - > refresh ( ) ;
2018-10-03 01:01:31 +01:00
this - > hasUnsavedChanges = true ;
}
void TilesetEditor : : closeEvent ( QCloseEvent * event )
{
if ( this - > hasUnsavedChanges ) {
2018-10-11 00:07:55 +01:00
QMessageBox : : StandardButton result = QMessageBox : : question (
this ,
" porymap " ,
" Tileset has been modified, save changes? " ,
QMessageBox : : No | QMessageBox : : Yes | QMessageBox : : Cancel ,
QMessageBox : : Yes ) ;
if ( result = = QMessageBox : : Yes ) {
this - > on_actionSave_Tileset_triggered ( ) ;
event - > accept ( ) ;
} else if ( result = = QMessageBox : : No ) {
2020-09-25 13:12:13 +01:00
this - > reset ( ) ;
2018-10-11 00:07:55 +01:00
event - > accept ( ) ;
} else if ( result = = QMessageBox : : Cancel ) {
event - > ignore ( ) ;
}
} else {
2018-10-03 01:01:31 +01:00
event - > accept ( ) ;
}
2020-09-15 19:57:46 +01:00
2020-09-25 13:12:13 +01:00
if ( event - > isAccepted ( ) ) {
if ( this - > paletteEditor ) this - > paletteEditor - > close ( ) ;
porymapConfig . setTilesetEditorGeometry (
this - > saveGeometry ( ) ,
this - > saveState ( )
) ;
}
2018-10-03 01:01:24 +01:00
}
2018-10-03 01:01:37 +01:00
void TilesetEditor : : on_actionChange_Metatiles_Count_triggered ( )
{
QDialog dialog ( this , Qt : : WindowTitleHint | Qt : : WindowCloseButtonHint ) ;
dialog . setWindowTitle ( " Change Number of Metatiles " ) ;
dialog . setWindowModality ( Qt : : NonModal ) ;
QFormLayout form ( & dialog ) ;
QSpinBox * primarySpinBox = new QSpinBox ( ) ;
QSpinBox * secondarySpinBox = new QSpinBox ( ) ;
primarySpinBox - > setMinimum ( 1 ) ;
secondarySpinBox - > setMinimum ( 1 ) ;
primarySpinBox - > setMaximum ( Project : : getNumMetatilesPrimary ( ) ) ;
secondarySpinBox - > setMaximum ( Project : : getNumMetatilesTotal ( ) - Project : : getNumMetatilesPrimary ( ) ) ;
2021-02-17 02:45:54 +00:00
primarySpinBox - > setValue ( this - > primaryTileset - > metatiles . length ( ) ) ;
secondarySpinBox - > setValue ( this - > secondaryTileset - > metatiles . length ( ) ) ;
2018-10-03 01:01:37 +01:00
form . addRow ( new QLabel ( " Primary Tileset " ) , primarySpinBox ) ;
form . addRow ( new QLabel ( " Secondary Tileset " ) , secondarySpinBox ) ;
QDialogButtonBox buttonBox ( QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel , Qt : : Horizontal , & dialog ) ;
2021-02-14 15:07:55 +00:00
connect ( & buttonBox , & QDialogButtonBox : : accepted , & dialog , & QDialog : : accept ) ;
connect ( & buttonBox , & QDialogButtonBox : : rejected , & dialog , & QDialog : : reject ) ;
2018-10-03 01:01:37 +01:00
form . addRow ( & buttonBox ) ;
if ( dialog . exec ( ) = = QDialog : : Accepted ) {
int numPrimaryMetatiles = primarySpinBox - > value ( ) ;
int numSecondaryMetatiles = secondarySpinBox - > value ( ) ;
2020-07-09 17:38:02 +01:00
int numTiles = projectConfig . getTripleLayerMetatilesEnabled ( ) ? 12 : 8 ;
2021-02-17 02:45:54 +00:00
while ( this - > primaryTileset - > metatiles . length ( ) > numPrimaryMetatiles ) {
delete this - > primaryTileset - > metatiles . takeLast ( ) ;
2018-10-03 01:01:37 +01:00
}
2021-02-17 02:45:54 +00:00
while ( this - > primaryTileset - > metatiles . length ( ) < numPrimaryMetatiles ) {
Tile tile ( 0 , false , false , 0 ) ;
2022-02-03 23:10:50 +00:00
Metatile * metatile = new Metatile ( ) ;
2020-07-09 17:38:02 +01:00
for ( int i = 0 ; i < numTiles ; i + + ) {
2021-02-16 17:14:27 +00:00
metatile - > tiles . append ( tile ) ;
2018-10-03 01:01:37 +01:00
}
2021-02-17 02:45:54 +00:00
this - > primaryTileset - > metatiles . append ( metatile ) ;
2018-10-03 01:01:37 +01:00
}
2021-02-17 02:45:54 +00:00
while ( this - > secondaryTileset - > metatiles . length ( ) > numSecondaryMetatiles ) {
delete this - > secondaryTileset - > metatiles . takeLast ( ) ;
2018-10-03 01:01:37 +01:00
}
2021-02-17 02:45:54 +00:00
while ( this - > secondaryTileset - > metatiles . length ( ) < numSecondaryMetatiles ) {
Tile tile ( 0 , false , false , 0 ) ;
2022-02-03 23:10:50 +00:00
Metatile * metatile = new Metatile ( ) ;
2020-07-09 17:38:02 +01:00
for ( int i = 0 ; i < numTiles ; i + + ) {
2021-02-16 17:14:27 +00:00
metatile - > tiles . append ( tile ) ;
2018-10-03 01:01:37 +01:00
}
2021-02-17 02:45:54 +00:00
this - > secondaryTileset - > metatiles . append ( metatile ) ;
2018-10-03 01:01:37 +01:00
}
2020-06-30 08:34:14 +01:00
this - > metatileSelector - > updateSelectedMetatile ( ) ;
2018-10-03 01:01:37 +01:00
this - > refresh ( ) ;
this - > hasUnsavedChanges = true ;
}
}
2018-10-03 01:01:41 +01:00
void TilesetEditor : : on_actionChange_Palettes_triggered ( )
{
if ( ! this - > paletteEditor ) {
2021-02-14 15:07:55 +00:00
this - > paletteEditor = new PaletteEditor ( this - > project , this - > primaryTileset ,
this - > secondaryTileset , this - > paletteId , this ) ;
connect ( this - > paletteEditor , & PaletteEditor : : changedPaletteColor ,
this , & TilesetEditor : : onPaletteEditorChangedPaletteColor ) ;
connect ( this - > paletteEditor , & PaletteEditor : : changedPalette ,
this , & TilesetEditor : : onPaletteEditorChangedPalette ) ;
2018-10-03 01:01:41 +01:00
}
if ( ! this - > paletteEditor - > isVisible ( ) ) {
this - > paletteEditor - > show ( ) ;
} else if ( this - > paletteEditor - > isMinimized ( ) ) {
this - > paletteEditor - > showNormal ( ) ;
} else {
this - > paletteEditor - > activateWindow ( ) ;
}
}
void TilesetEditor : : onPaletteEditorChangedPaletteColor ( ) {
this - > refresh ( ) ;
this - > hasUnsavedChanges = true ;
}
void TilesetEditor : : onPaletteEditorChangedPalette ( int paletteId ) {
this - > on_spinBox_paletteSelector_valueChanged ( paletteId ) ;
}
2018-10-06 23:07:36 +01:00
2022-03-30 23:03:13 +01:00
bool TilesetEditor : : replaceMetatile ( uint16_t metatileId , Metatile * src )
{
Metatile * dest = Tileset : : getMetatile ( metatileId , this - > primaryTileset , this - > secondaryTileset ) ;
2022-06-29 19:53:14 +01:00
if ( ! dest | | ! src | | * dest = = * src )
2022-03-30 23:03:13 +01:00
return false ;
this - > metatile = dest ;
* this - > metatile = * src ;
this - > metatileSelector - > select ( metatileId ) ;
this - > metatileSelector - > draw ( ) ;
this - > metatileLayersItem - > draw ( ) ;
this - > metatileLayersItem - > clearLastModifiedCoords ( ) ;
return true ;
}
2018-10-06 23:07:36 +01:00
void TilesetEditor : : on_actionUndo_triggered ( )
{
MetatileHistoryItem * commit = this - > metatileHistory . current ( ) ;
if ( ! commit ) return ;
Metatile * prev = commit - > prevMetatile ;
if ( ! prev ) return ;
this - > metatileHistory . back ( ) ;
2022-03-30 23:03:13 +01:00
this - > replaceMetatile ( commit - > metatileId , prev ) ;
2018-10-06 23:07:36 +01:00
}
void TilesetEditor : : on_actionRedo_triggered ( )
{
MetatileHistoryItem * commit = this - > metatileHistory . next ( ) ;
if ( ! commit ) return ;
2022-03-30 23:03:13 +01:00
this - > replaceMetatile ( commit - > metatileId , commit - > newMetatile ) ;
}
void TilesetEditor : : on_actionCopy_triggered ( )
{
Metatile * toCopy = Tileset : : getMetatile ( this - > getSelectedMetatileId ( ) , this - > primaryTileset , this - > secondaryTileset ) ;
if ( ! toCopy ) return ;
if ( ! this - > copiedMetatile )
this - > copiedMetatile = new Metatile ( * toCopy ) ;
else
* this - > copiedMetatile = * toCopy ;
this - > copiedMetatile - > label = " " ; // Don't copy the label, these should be unique to each metatile
}
void TilesetEditor : : on_actionPaste_triggered ( )
{
Metatile * prevMetatile = new Metatile ( * this - > metatile ) ;
uint16_t metatileId = this - > getSelectedMetatileId ( ) ;
if ( ! this - > replaceMetatile ( metatileId , this - > copiedMetatile ) )
return ;
MetatileHistoryItem * commit = new MetatileHistoryItem ( metatileId , prevMetatile , new Metatile ( * this - > metatile ) ) ;
metatileHistory . push ( commit ) ;
2018-10-06 23:07:36 +01:00
}
2019-01-05 21:52:55 +00:00
void TilesetEditor : : on_actionExport_Primary_Tiles_Image_triggered ( )
{
QString defaultName = QString ( " %1_Tiles_Pal%2 " ) . arg ( this - > primaryTileset - > name ) . arg ( this - > paletteId ) ;
QString defaultFilepath = QString ( " %1/%2.png " ) . arg ( this - > project - > root ) . arg ( defaultName ) ;
QString filepath = QFileDialog : : getSaveFileName ( this , " Export Primary Tiles Image " , defaultFilepath , " Image Files (*.png) " ) ;
if ( ! filepath . isEmpty ( ) ) {
QImage image = this - > tileSelector - > buildPrimaryTilesIndexedImage ( ) ;
2019-01-11 14:52:47 +00:00
exportIndexed4BPPPng ( image , filepath ) ;
2019-01-05 21:52:55 +00:00
}
}
void TilesetEditor : : on_actionExport_Secondary_Tiles_Image_triggered ( )
{
QString defaultName = QString ( " %1_Tiles_Pal%2 " ) . arg ( this - > secondaryTileset - > name ) . arg ( this - > paletteId ) ;
QString defaultFilepath = QString ( " %1/%2.png " ) . arg ( this - > project - > root ) . arg ( defaultName ) ;
QString filepath = QFileDialog : : getSaveFileName ( this , " Export Secondary Tiles Image " , defaultFilepath , " Image Files (*.png) " ) ;
if ( ! filepath . isEmpty ( ) ) {
QImage image = this - > tileSelector - > buildSecondaryTilesIndexedImage ( ) ;
2019-01-11 14:52:47 +00:00
exportIndexed4BPPPng ( image , filepath ) ;
2019-01-05 21:52:55 +00:00
}
}
2019-01-09 00:04:41 +00:00
void TilesetEditor : : on_actionImport_Primary_Metatiles_triggered ( )
{
this - > importTilesetMetatiles ( this - > primaryTileset , true ) ;
}
void TilesetEditor : : on_actionImport_Secondary_Metatiles_triggered ( )
{
this - > importTilesetMetatiles ( this - > secondaryTileset , false ) ;
}
void TilesetEditor : : importTilesetMetatiles ( Tileset * tileset , bool primary )
{
QString descriptor = primary ? " primary " : " secondary " ;
QString descriptorCaps = primary ? " Primary " : " Secondary " ;
QString filepath = QFileDialog : : getOpenFileName (
this ,
QString ( " Import %1 Tileset Metatiles from Advance Map 1.92 " ) . arg ( descriptorCaps ) ,
this - > project - > root ,
" Advance Map 1.92 Metatile Files (*.bvd) " ) ;
if ( filepath . isEmpty ( ) ) {
return ;
}
bool error = false ;
2021-02-18 08:38:34 +00:00
QList < Metatile * > metatiles = MetatileParser : : parse ( filepath , & error , primary ) ;
2019-01-09 00:04:41 +00:00
if ( error ) {
QMessageBox msgBox ( this ) ;
msgBox . setText ( " Failed to import metatiles from Advance Map 1.92 .bvd file. " ) ;
QString message = QString ( " The .bvd file could not be processed. View porymap.log for specific errors. " ) ;
msgBox . setInformativeText ( message ) ;
msgBox . setDefaultButton ( QMessageBox : : Ok ) ;
msgBox . setIcon ( QMessageBox : : Icon : : Critical ) ;
msgBox . exec ( ) ;
return ;
}
2019-04-04 06:44:31 +01:00
2019-01-09 00:04:41 +00:00
// TODO: This is crude because it makes a history entry for every newly-imported metatile.
// Revisit this when tiles and num metatiles are added to tileset editory history.
int metatileIdBase = primary ? 0 : Project : : getNumMetatilesPrimary ( ) ;
2021-02-17 02:45:54 +00:00
for ( int i = 0 ; i < metatiles . length ( ) ; i + + ) {
if ( i > = tileset - > metatiles . length ( ) ) {
2019-01-09 00:04:41 +00:00
break ;
}
2021-02-17 02:45:54 +00:00
Metatile * prevMetatile = new Metatile ( * tileset - > metatiles . at ( i ) ) ;
2021-02-16 18:22:41 +00:00
MetatileHistoryItem * commit = new MetatileHistoryItem ( static_cast < uint16_t > ( metatileIdBase + i ) ,
2021-02-17 02:45:54 +00:00
prevMetatile , new Metatile ( * metatiles . at ( i ) ) ) ;
2019-01-09 00:04:41 +00:00
metatileHistory . push ( commit ) ;
}
tileset - > metatiles = metatiles ;
this - > refresh ( ) ;
this - > hasUnsavedChanges = true ;
}
2021-07-20 03:02:31 +01:00
void TilesetEditor : : on_actionShow_Unused_toggled ( bool checked ) {
this - > metatileSelector - > selectorShowUnused = checked ;
if ( checked ) countMetatileUsage ( ) ;
this - > metatileSelector - > draw ( ) ;
}
void TilesetEditor : : on_actionShow_Counts_toggled ( bool checked ) {
this - > metatileSelector - > selectorShowCounts = checked ;
if ( checked ) countMetatileUsage ( ) ;
this - > metatileSelector - > draw ( ) ;
}
2021-07-21 23:55:33 +01:00
void TilesetEditor : : on_actionShow_UnusedTiles_toggled ( bool checked ) {
this - > tileSelector - > showUnused = checked ;
if ( checked ) countTileUsage ( ) ;
this - > tileSelector - > draw ( ) ;
}
2021-07-20 03:02:31 +01:00
void TilesetEditor : : countMetatileUsage ( ) {
// do not double count
metatileSelector - > usedMetatiles . fill ( 0 ) ;
for ( auto layout : this - > project - > mapLayouts . values ( ) ) {
bool usesPrimary = false ;
bool usesSecondary = false ;
if ( layout - > tileset_primary_label = = this - > primaryTileset - > name ) {
usesPrimary = true ;
}
if ( layout - > tileset_secondary_label = = this - > secondaryTileset - > name ) {
usesSecondary = true ;
}
if ( usesPrimary | | usesSecondary ) {
this - > project - > loadLayout ( layout ) ;
// for each block in the layout, mark in the vector that it is used
for ( int i = 0 ; i < layout - > blockdata . length ( ) ; i + + ) {
2021-11-24 04:53:41 +00:00
uint16_t metatileId = layout - > blockdata . at ( i ) . metatileId ;
if ( metatileId < this - > project - > getNumMetatilesPrimary ( ) ) {
if ( usesPrimary ) metatileSelector - > usedMetatiles [ metatileId ] + + ;
2021-07-20 03:02:31 +01:00
} else {
2021-11-24 04:53:41 +00:00
if ( usesSecondary ) metatileSelector - > usedMetatiles [ metatileId ] + + ;
2021-07-20 03:02:31 +01:00
}
}
for ( int i = 0 ; i < layout - > border . length ( ) ; i + + ) {
2021-11-24 04:53:41 +00:00
uint16_t metatileId = layout - > border . at ( i ) . metatileId ;
if ( metatileId < this - > project - > getNumMetatilesPrimary ( ) ) {
if ( usesPrimary ) metatileSelector - > usedMetatiles [ metatileId ] + + ;
2021-07-20 03:02:31 +01:00
} else {
2021-11-24 04:53:41 +00:00
if ( usesSecondary ) metatileSelector - > usedMetatiles [ metatileId ] + + ;
2021-07-20 03:02:31 +01:00
}
}
}
}
}
2021-07-21 23:55:33 +01:00
void TilesetEditor : : countTileUsage ( ) {
// check primary tiles
this - > tileSelector - > usedTiles . resize ( Project : : getNumTilesTotal ( ) ) ;
this - > tileSelector - > usedTiles . fill ( 0 ) ;
QSet < Tileset * > primaryTilesets ;
QSet < Tileset * > secondaryTilesets ;
for ( auto layout : this - > project - > mapLayouts . values ( ) ) {
if ( layout - > tileset_primary_label = = this - > primaryTileset - > name
| | layout - > tileset_secondary_label = = this - > secondaryTileset - > name ) {
this - > project - > loadLayoutTilesets ( layout ) ;
// need to check metatiles
if ( layout - > tileset_primary & & layout - > tileset_secondary ) {
primaryTilesets . insert ( layout - > tileset_primary ) ;
secondaryTilesets . insert ( layout - > tileset_secondary ) ;
}
}
}
// check primary tilesets that are used with this secondary tileset for
// reference to secondary tiles in primary metatiles
for ( Tileset * tileset : primaryTilesets ) {
for ( Metatile * metatile : tileset - > metatiles ) {
for ( Tile tile : metatile - > tiles ) {
2021-11-24 04:53:41 +00:00
if ( tile . tileId > = Project : : getNumTilesPrimary ( ) )
this - > tileSelector - > usedTiles [ tile . tileId ] + + ;
2021-07-21 23:55:33 +01:00
}
}
}
// do the opposite for primary tiles in secondary metatiles
for ( Tileset * tileset : secondaryTilesets ) {
for ( Metatile * metatile : tileset - > metatiles ) {
for ( Tile tile : metatile - > tiles ) {
2021-11-24 04:53:41 +00:00
if ( tile . tileId < Project : : getNumTilesPrimary ( ) )
this - > tileSelector - > usedTiles [ tile . tileId ] + + ;
2021-07-21 23:55:33 +01:00
}
}
}
// check this primary tileset metatiles
for ( Metatile * metatile : this - > primaryTileset - > metatiles ) {
for ( Tile tile : metatile - > tiles ) {
2021-11-24 04:53:41 +00:00
this - > tileSelector - > usedTiles [ tile . tileId ] + + ;
2021-07-21 23:55:33 +01:00
}
}
// and the secondary metatiles
for ( Metatile * metatile : this - > secondaryTileset - > metatiles ) {
for ( Tile tile : metatile - > tiles ) {
2021-11-24 04:53:41 +00:00
this - > tileSelector - > usedTiles [ tile . tileId ] + + ;
2021-07-21 23:55:33 +01:00
}
}
}