From 31819d246dfd84f3af297629568167829c2bff6f Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Tue, 2 Feb 2021 22:37:01 -0500 Subject: [PATCH] Added initial framework for Qt palette editor window. --- src/CMakeLists.txt | 1 + src/drivers/Qt/ConsoleWindow.cpp | 20 ++ src/drivers/Qt/ConsoleWindow.h | 59 ++-- src/drivers/Qt/PaletteEditor.cpp | 573 +++++++++++++++++++++++++++++++ src/drivers/Qt/PaletteEditor.h | 86 +++++ 5 files changed, 710 insertions(+), 29 deletions(-) create mode 100644 src/drivers/Qt/PaletteEditor.cpp create mode 100644 src/drivers/Qt/PaletteEditor.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7abe867e..033009d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -437,6 +437,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FrameTimingStats.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteEditor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MovieOptions.cpp diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index a676ca52..44a19a90 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -53,6 +53,7 @@ #include "Qt/GamePadConf.h" #include "Qt/HotKeyConf.h" #include "Qt/PaletteConf.h" +#include "Qt/PaletteEditor.h" #include "Qt/GuiConf.h" #include "Qt/MoviePlay.h" #include "Qt/MovieOptions.h" @@ -753,6 +754,14 @@ void consoleWin_t::createMainMenu(void) act->setStatusTip(tr("Open Frame Timing Window")); connect(act, SIGNAL(triggered()), this, SLOT(openTimingStatWin(void)) ); + toolsMenu->addAction(act); + + // Tools -> Palette Editor + act = new QAction(tr("Palette Editor ..."), this); + //act->setShortcut( QKeySequence(tr("Shift+F7"))); + act->setStatusTip(tr("Open Palette Editor Window")); + connect(act, SIGNAL(triggered()), this, SLOT(openPaletteEditorWin(void)) ); + toolsMenu->addAction(act); //----------------------------------------------------------------------- @@ -1433,6 +1442,17 @@ void consoleWin_t::openTimingStatWin(void) tmStatWin->show(); } +void consoleWin_t::openPaletteEditorWin(void) +{ + PaletteEditorDialog_t *win; + + //printf("Open Palette Editor Window\n"); + + win = new PaletteEditorDialog_t(this); + + win->show(); +} + void consoleWin_t::openMovieOptWin(void) { MovieOptionsDialog_t *win; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 56077452..b6b0518d 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -167,8 +167,8 @@ class consoleWin_t : public QMainWindow public slots: void openDebugWindow(void); void openHexEditor(void); - void openGamePadConfWin(void); - void toggleFullscreen(void); + void openGamePadConfWin(void); + void toggleFullscreen(void); void toggleMenuVis(void); private slots: void closeApp(void); @@ -179,35 +179,36 @@ class consoleWin_t : public QMainWindow void quickLoad(void); void quickSave(void); void closeROMCB(void); - void aboutFCEUX(void); - void aboutQt(void); - void openMsgLogWin(void); - void openInputConfWin(void); - void openGameSndConfWin(void); - void openGameVideoConfWin(void); - void openHotkeyConfWin(void); - void openPaletteConfWin(void); - void openGuiConfWin(void); - void openTimingConfWin(void); - void openTimingStatWin(void); - void openMovieOptWin(void); + void aboutFCEUX(void); + void aboutQt(void); + void openMsgLogWin(void); + void openInputConfWin(void); + void openGameSndConfWin(void); + void openGameVideoConfWin(void); + void openHotkeyConfWin(void); + void openPaletteConfWin(void); + void openGuiConfWin(void); + void openTimingConfWin(void); + void openPaletteEditorWin(void); + void openTimingStatWin(void); + void openMovieOptWin(void); void openCodeDataLogger(void); void openTraceLogger(void); - void toggleAutoResume(void); - void updatePeriodic(void); - void changeState0(void); - void changeState1(void); - void changeState2(void); - void changeState3(void); - void changeState4(void); - void changeState5(void); - void changeState6(void); - void changeState7(void); - void changeState8(void); - void changeState9(void); - void loadLua(void); - void takeScreenShot(void); - void powerConsoleCB(void); + void toggleAutoResume(void); + void updatePeriodic(void); + void changeState0(void); + void changeState1(void); + void changeState2(void); + void changeState3(void); + void changeState4(void); + void changeState5(void); + void changeState6(void); + void changeState7(void); + void changeState8(void); + void changeState9(void); + void loadLua(void); + void takeScreenShot(void); + void powerConsoleCB(void); void consoleHardReset(void); void consoleSoftReset(void); void consolePause(void); diff --git a/src/drivers/Qt/PaletteEditor.cpp b/src/drivers/Qt/PaletteEditor.cpp new file mode 100644 index 00000000..6536b829 --- /dev/null +++ b/src/drivers/Qt/PaletteEditor.cpp @@ -0,0 +1,573 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 mjbudd77 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// PaletteEditor.cpp +// +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../cart.h" +#include "../../ppu.h" +#include "../../debug.h" +#include "../../palette.h" + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/PaletteEditor.h" + +//---------------------------------------------------------------------------- +PaletteEditorDialog_t::PaletteEditorDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + QMenuBar *menuBar; + QMenu *fileMenu; + QAction *act; + int useNativeMenuBar; + + setWindowTitle("Palette Editor"); + //resize( 512, 512 ); + + menuBar = new QMenuBar(this); + + // This is needed for menu bar to show up on MacOS + g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar ); + + menuBar->setNativeMenuBar( useNativeMenuBar ? true : false ); + + //----------------------------------------------------------------------- + // Menu + //----------------------------------------------------------------------- + // File + fileMenu = menuBar->addMenu(tr("File")); + + // File -> Open + act = new QAction(tr("Open"), this); + act->setShortcut(QKeySequence::Open); + act->setStatusTip(tr("Open Palette From File")); + connect(act, SIGNAL(triggered()), this, SLOT(openPaletteFileDialog(void)) ); + + fileMenu->addAction(act); + + // File -> Save + act = new QAction(tr("Save"), this); + act->setShortcut( QKeySequence::Save ); + act->setStatusTip(tr("Save Palette To File")); + connect(act, SIGNAL(triggered()), this, SLOT(savePaletteFileDialog(void)) ); + + fileMenu->addAction(act); + + // File -> Load + act = new QAction(tr("Load"), this); + act->setShortcut( QKeySequence(tr("F5"))); + act->setStatusTip(tr("Load Palette Memory")); + connect(act, SIGNAL(triggered()), this, SLOT(setActivePalette(void)) ); + + fileMenu->addAction(act); + + //----------------------------------------------------------------------- + // End Menu + //----------------------------------------------------------------------- + + mainLayout = new QVBoxLayout(); + + mainLayout->setMenuBar( menuBar ); + + setLayout( mainLayout ); + + palView = new nesPaletteView(this); + + mainLayout->addWidget( palView ); + + palView->loadActivePalette(); +} +//---------------------------------------------------------------------------- +PaletteEditorDialog_t::~PaletteEditorDialog_t(void) +{ + printf("Destroy Palette Editor Config Window\n"); +} +//---------------------------------------------------------------------------- +void PaletteEditorDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Palette Editor Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void PaletteEditorDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- +void PaletteEditorDialog_t::setActivePalette(void) +{ + palView->setActivePalette(); +} +//---------------------------------------------------------------------------- +void PaletteEditorDialog_t::openPaletteFileDialog(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + QFileDialog dialog(this, tr("Open Palette From File") ); + + const QStringList filters( + { + "Palette Files (*.pal *.Pal)", + "Any files (*)" + }); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilters( filters ); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); + + dialog.setDirectory( tr("/usr/share/fceux/palettes") ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + palView->loadFromFile( filename.toStdString().c_str() ); + + return; +} +//---------------------------------------------------------------------------- +void PaletteEditorDialog_t::savePaletteFileDialog(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + QFileDialog dialog(this, tr("Save Palette To File") ); + const char *home; + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("Pal Files (*.pal *.PAL) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + dialog.setDefaultSuffix( tr(".pal") ); + + home = ::getenv("HOME"); + + if ( home ) + { + dialog.setDirectory( tr(home) ); + } + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + palView->saveToFile( filename.toStdString().c_str() ); +} +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +nesPaletteView::nesPaletteView( QWidget *parent) + : QWidget(parent) +{ + this->setFocusPolicy(Qt::StrongFocus); + this->setMouseTracking(true); + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + //font.setPixelSize( boxPixSize / 3 ); + QFontMetrics fm(font); + + #if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + pxCharWidth = fm.horizontalAdvance(QLatin1Char('2')); + #else + pxCharWidth = fm.width(QLatin1Char('2')); + #endif + pxCharHeight = fm.height(); + + boxWidth = pxCharWidth * 4; + boxHeight = pxCharHeight * 2; + + viewWidth = boxWidth * 16; + viewHeight = boxHeight * 4; + setMinimumWidth( viewWidth ); + setMinimumHeight( viewHeight ); +} +//---------------------------------------------------------------------------- +nesPaletteView::~nesPaletteView(void) +{ + +} +//---------------------------------------------------------------------------- +void nesPaletteView::loadActivePalette(void) +{ + if ( palo == NULL ) + { + return; + } + + for (int p=0; p= (3*0x40) ) + { + + for (i=0; isize().width(); + //viewHeight = event->size().height(); + + //boxWidth = viewWidth / 16; + //boxHeight = viewHeight / 4; +} +//---------------------------------------------------- +void nesPaletteView::keyPressEvent(QKeyEvent *event) +{ + //printf("NES Palette View Key Press: 0x%x \n", event->key() ); + + if ( event->key() == Qt::Key_E ) + { + openColorPicker( &color[ selCell.y()*16 + selCell.x() ] ); + + event->accept(); + } + + event->ignore(); +} +//---------------------------------------------------- +void nesPaletteView::mouseMoveEvent(QMouseEvent *event) +{ + QPoint cell = convPixToCell( event->pos() ); + + //printf("Cell %X%X\n", cell.y(), cell.x() ); + + if ( (cell.x() >= 0) && (cell.x() < 16) && + (cell.y() >= 0) && (cell.y() < 4) ) + { + selCell = cell; + } +} +//---------------------------------------------------------------------------- +void nesPaletteView::mousePressEvent(QMouseEvent * event) +{ + //QPoint cell = convPixToCell( event->pos() ); + + if ( event->button() == Qt::LeftButton ) + { + // Set Cell + //setSelCell( cell ); + } +} +//---------------------------------------------------------------------------- +void nesPaletteView::contextMenuEvent(QContextMenuEvent *event) +{ + QAction *act; + QMenu menu(this); + //QMenu *subMenu; + //QActionGroup *group; + char stmp[64]; + + sprintf( stmp, "Edit Color %X%X", selCell.y(), selCell.x() ); + act = new QAction(tr(stmp), &menu); + act->setShortcut( QKeySequence(tr("E"))); + connect( act, SIGNAL(triggered(void)), this, SLOT(editSelColor(void)) ); + menu.addAction( act ); + + menu.exec(event->globalPos()); +} +//---------------------------------------------------------------------------- +void nesPaletteView::editSelColor(void) +{ + openColorPicker( &color[ selCell.y()*16 + selCell.x() ] ); +} +//---------------------------------------------------------------------------- +QPoint nesPaletteView::convPixToCell( QPoint p ) +{ + int x,y; + QPoint c; + + x = p.x(); + y = p.y(); + + c.setX( x / boxWidth ); + c.setY( y / boxHeight); + + return c; +} +//---------------------------------------------------------------------------- +void nesPaletteView::openColorPicker( QColor *c ) +{ + int ret; + QColorDialog dialog( this ); + + dialog.setCurrentColor( *c ); + dialog.setOption( QColorDialog::DontUseNativeDialog, true ); + dialog.show(); + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + *c = dialog.selectedColor(); + } +} +//---------------------------------------------------------------------------- +static int conv2hex( int i ) +{ + int h = 0; + if ( i >= 10 ) + { + h = 'A' + i - 10; + } + else + { + h = '0' + i; + } + return h; +} +//---------------------------------------------------------------------------- +void nesPaletteView::paintEvent(QPaintEvent *event) +{ + int x,y,w,h,xx,yy,ii,i,j; + QPainter painter(this); + QPen pen; + char c[4]; + QColor white(255,255,255), black(0,0,0); + + pen = painter.pen(); + + viewWidth = event->rect().width(); + viewHeight = event->rect().height(); + + //printf("PPU nesPaletteView %ix%i \n", viewWidth, viewHeight ); + + w = viewWidth / 16; + h = viewHeight / 4; + + boxWidth = w; + boxHeight = h; + + xx = 0; yy = 0; + + if ( w < h ) + { + h = w; + } + else + { + w = h; + } + + i = w / 4; + j = h / 4; + + ii=0; + + // Draw Tile Pixels as rectangles + for (y=0; y < 4; y++) + { + xx = 0; + + for (x=0; x < 16; x++) + { + c[0] = conv2hex( (ii & 0xF0) >> 4 ); + c[1] = conv2hex( ii & 0x0F); + c[2] = 0; + + painter.fillRect( xx, yy, w, h, color[ ii ] ); + + if ( qGray( color[ii].red(), color[ii].green(), color[ii].blue() ) > 128 ) + { + painter.setPen( black ); + } + else + { + painter.setPen( white ); + } + painter.drawText( xx+i, yy+h-j, tr(c) ); + + xx += w; ii++; + } + yy += h; + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/PaletteEditor.h b/src/drivers/Qt/PaletteEditor.h new file mode 100644 index 00000000..4a62bd4a --- /dev/null +++ b/src/drivers/Qt/PaletteEditor.h @@ -0,0 +1,86 @@ +// PaletteEditor.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class nesPaletteView : public QWidget +{ + Q_OBJECT + + public: + nesPaletteView( QWidget *parent = 0); + ~nesPaletteView(void); + + static const int NUM_COLORS = 0x40; + + QColor color[ NUM_COLORS ]; + + void loadActivePalette(void); + QPoint convPixToCell( QPoint p ); + + void setActivePalette(void); + void openColorPicker( QColor *c ); + int loadFromFile( const char *filepath ); + int saveToFile( const char *filepath ); + + protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + void keyPressEvent(QKeyEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent * event); + void contextMenuEvent(QContextMenuEvent *event); + + QFont font; + QPoint selCell; + + int viewWidth; + int viewHeight; + int boxWidth; + int boxHeight; + int pxCharWidth; + int pxCharHeight; + + private slots: + void editSelColor(void); +}; + +class PaletteEditorDialog_t : public QDialog +{ + Q_OBJECT + + public: + PaletteEditorDialog_t(QWidget *parent = 0); + ~PaletteEditorDialog_t(void); + + nesPaletteView *palView; + + protected: + void closeEvent(QCloseEvent *event); + + private: + + public slots: + void closeWindow(void); + private slots: + void openPaletteFileDialog(void); + void savePaletteFileDialog(void); + void setActivePalette(void); + +};