-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial version of palette editor
- Loading branch information
Showing
1 changed file
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import sys | ||
from PyQt4 import QtGui, QtCore | ||
from functools import partial | ||
|
||
import parse_game_config | ||
import parse_stage_config | ||
|
||
class Window(QtGui.QMainWindow): | ||
|
||
def __init__(self): | ||
super(Window, self).__init__() | ||
|
||
choose_file = QtGui.QFileDialog.getOpenFileName(self, "Open Config File", "", "Sonic Mania Config File (GameConfig.bin; StageConfig.bin)"); | ||
|
||
if not choose_file: | ||
sys.exit() | ||
|
||
self.filename = str(choose_file) | ||
try: | ||
if self.filename.endswith("GameConfig.bin"): | ||
self.cfg = parse_game_config.CFG.parse(open(self.filename, "rb").read()) | ||
else: | ||
self.cfg = parse_stage_config.CFG.parse(open(self.filename, "rb").read()) | ||
except: | ||
msg = QtGui.QMessageBox() | ||
msg.setIcon(QtGui.QMessageBox.Critical) | ||
|
||
msg.setText("Failed to load configuration file") | ||
msg.setWindowTitle("Error") | ||
msg.setStandardButtons(QtGui.QMessageBox.Close) | ||
|
||
msg.exec_() | ||
sys.exit() | ||
|
||
self.setGeometry(50, 50, 530, 560) | ||
self.setWindowTitle("Sonic Mania Palette Editor") | ||
#self.setWindowIcon(QtGui.QIcon('pythonlogo.png')) | ||
|
||
saveAction = QtGui.QAction("&Save", self) | ||
saveAction.setShortcut("Ctrl+S") | ||
saveAction.triggered.connect(self.save) | ||
|
||
exitAction = QtGui.QAction("&Exit", self) | ||
exitAction.setShortcut("Ctrl+Q") | ||
exitAction.triggered.connect(self.close_application) | ||
|
||
self.statusBar() | ||
|
||
mainMenu = self.menuBar() | ||
fileMenu = mainMenu.addMenu('&File') | ||
fileMenu.addAction(saveAction) | ||
fileMenu.addAction(exitAction) | ||
|
||
self.checkboxs = [] | ||
for i in xrange(16): | ||
checkBox = QtGui.QCheckBox("", self) | ||
checkBox.move(10, 70 + i * 30) | ||
checkBox.stateChanged.connect(partial(self.click_checkbox, i)) | ||
self.checkboxs.append(checkBox) | ||
|
||
self.columns = [] | ||
for i in xrange(16): | ||
pixels = [] | ||
self.columns.append(pixels) | ||
for j in xrange(16): | ||
pixel = QtGui.QPushButton("", self) | ||
pixels.append(pixel) | ||
pixel.resize(25, 25) | ||
self.update_pixel_color(i, j, None) | ||
pixel.move(34 + j * 30, 72 + i * 30) | ||
pixel.clicked.connect(partial(self.set_color, i, j)) | ||
|
||
for i in xrange(8): | ||
palette = QtGui.QPushButton("#%d" % i, self) | ||
palette.resize(60, palette.height()) | ||
palette.move(15 + i * 63, 32) | ||
palette.clicked.connect(partial(self.load_palette, i)) | ||
|
||
self.current_palette = 0 | ||
self.changes = False | ||
self.load_palette(0) | ||
|
||
self.show() | ||
|
||
def save(self): | ||
if self.changes: | ||
choice = QtGui.QMessageBox.question(self, 'Warning', | ||
"Are you sure that you want to save the changes?", | ||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) | ||
if choice == QtGui.QMessageBox.Yes: | ||
try: | ||
if self.filename.endswith("GameConfig.bin"): | ||
open(self.filename, "wb").write(parse_game_config.CFG.build(self.cfg)) | ||
else: | ||
open(self.filename, "wb").write(parse_stage_config.CFG.build(self.cfg)) | ||
self.changes = False | ||
except: | ||
msg = QtGui.QMessageBox() | ||
msg.setIcon(QtGui.QMessageBox.Critical) | ||
|
||
msg.setText("Failed to save configuration file") | ||
msg.setWindowTitle("Error") | ||
msg.setStandardButtons(QtGui.QMessageBox.Close) | ||
|
||
msg.exec_() | ||
|
||
def update_pixel_color(self, col, row, color): | ||
if color is None: | ||
self.columns[col][row].setStyleSheet("QWidget { background-color: rgb(220,220,220); border-color: rgb(150,150,150); border-width: 1; border-style: outset; }") | ||
else: | ||
self.columns[col][row].setStyleSheet("QWidget { background-color: rgb(%d,%d,%d); border-color: black; border-width: 1; border-style: outset; }" % (color["R"], color["G"], color["B"])) | ||
|
||
def update_column_colors(self, col, pixels): | ||
for i in xrange(16): | ||
if pixels: | ||
self.update_pixel_color(col, i, pixels[i]) | ||
else: | ||
self.update_pixel_color(col, i, None) | ||
|
||
def load_palette(self, index): | ||
before_changes = self.changes | ||
self.current_palette = index | ||
for i in xrange(16): | ||
if self.cfg.Palettes[index].Bitmap & (1 << i): | ||
self.checkboxs[i].setChecked(True) | ||
self.update_column_colors(i, self.cfg.Palettes[index].Columns[i].Pixels) | ||
else: | ||
self.checkboxs[i].setChecked(False) | ||
self.update_column_colors(i, None) | ||
self.changes = before_changes | ||
|
||
def click_checkbox(self, col, state): | ||
if state == QtCore.Qt.Checked: | ||
if not self.cfg.Palettes[self.current_palette].Columns[col].Pixels: | ||
pixels = [{"R":0,"G":0,"B":0} for i in xrange(16)] | ||
self.cfg.Palettes[self.current_palette].Columns[col].Pixels = pixels | ||
self.cfg.Palettes[self.current_palette].Bitmap |= 1 << col | ||
self.update_column_colors(col, self.cfg.Palettes[self.current_palette].Columns[col].Pixels) | ||
else: | ||
self.cfg.Palettes[self.current_palette].Bitmap &= ~(1 << col) | ||
self.update_column_colors(col, None) | ||
self.changes = True | ||
|
||
def set_color(self, col, row): | ||
if self.checkboxs[col].isChecked(): | ||
dlg = QtGui.QColorDialog(self) | ||
current_pixel = self.cfg.Palettes[self.current_palette].Columns[col].Pixels[row] | ||
dlg.setCurrentColor(QtGui.QColor(current_pixel["R"], current_pixel["G"], current_pixel["B"])) | ||
if dlg.exec_(): | ||
color = dlg.selectedColor() | ||
self.changes = True | ||
pixel = {"R": color.red(), "G": color.green(), "B": color.blue()} | ||
self.cfg.Palettes[self.current_palette].Columns[col].Pixels[row] = pixel | ||
self.update_pixel_color(col, row, pixel) | ||
|
||
def close_application(self): | ||
if not self.changes: | ||
sys.exit() | ||
choice = QtGui.QMessageBox.question(self, 'Warning', | ||
"There are unsaved changes, exit?", | ||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) | ||
if choice == QtGui.QMessageBox.Yes: | ||
sys.exit() | ||
else: | ||
pass | ||
|
||
def closeEvent(self, event): | ||
if self.changes: | ||
choice = QtGui.QMessageBox.question(self, 'Warning', | ||
"There are unsaved changes, exit?", | ||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) | ||
if choice == QtGui.QMessageBox.Yes: | ||
event.accept() | ||
else: | ||
event.ignore() | ||
else: | ||
event.accept() | ||
|
||
def run(): | ||
app = QtGui.QApplication(sys.argv) | ||
GUI = Window() | ||
sys.exit(app.exec_()) | ||
|
||
run() |