Added FF4 character battle sprites
This commit is contained in:
parent
2d286d48ef
commit
d32ca0608e
|
@ -1,4 +1,4 @@
|
|||
#!python3 -i
|
||||
#!/usr/bin/python3 -i
|
||||
'''
|
||||
No license for now
|
||||
'''
|
||||
|
@ -13,9 +13,10 @@ import const
|
|||
import time
|
||||
|
||||
pyqt_version = 0
|
||||
skip_pyqt5 = "PYQT4" in os.environ
|
||||
filename_en = "Final Fantasy V (Japan) [En by RPGe v1.1].sfc"
|
||||
filename_jp = "Final Fantasy V (Japan).sfc"
|
||||
skip_pyqt5 = 'PYQT4' in os.environ
|
||||
filename_en = 'Final Fantasy V (Japan) [En by RPGe v1.1].sfc'
|
||||
filename_jp = 'Final Fantasy V (Japan).sfc'
|
||||
filename_jp_ff4 = 'Final Fantasy IV (Japan) (Rev A).sfc'
|
||||
|
||||
if not skip_pyqt5:
|
||||
try:
|
||||
|
@ -39,7 +40,7 @@ if not skip_pyqt5:
|
|||
pyqt_version = 5
|
||||
except ImportError:
|
||||
print("Couldn't import Qt5 dependencies. "
|
||||
"Make sure you installed the PyQt5 package.")
|
||||
'Make sure you installed the PyQt5 package.')
|
||||
if pyqt_version == 0:
|
||||
try:
|
||||
import sip
|
||||
|
@ -66,18 +67,20 @@ if pyqt_version == 0:
|
|||
pyqt_version = 4
|
||||
except ImportError:
|
||||
print("Couldn't import Qt dependencies. "
|
||||
"Make sure you installed the PyQt4 package.")
|
||||
'Make sure you installed the PyQt4 package.')
|
||||
sys.exit(-1)
|
||||
|
||||
bg_color = QColor(0, 0, 128)
|
||||
bg_trans = QColor(0, 0, 0, 0)
|
||||
|
||||
HEX_PREFIX = '#' # '$' or '0x' are also nice
|
||||
|
||||
monofont = QFont()
|
||||
monofont.setStyleHint(QFont.Monospace)
|
||||
if not monofont.fixedPitch():
|
||||
monofont.setStyleHint(QFont.TypeWriter)
|
||||
if not monofont.fixedPitch():
|
||||
monofont.setFamily("Monospace")
|
||||
monofont.setFamily('Monospace')
|
||||
|
||||
def divceil(numerator, denominator):
|
||||
# Reverse floor division for ceil
|
||||
|
@ -86,15 +89,18 @@ def divceil(numerator, denominator):
|
|||
def hex_length(i):
|
||||
return divceil(i.bit_length(), 4)
|
||||
|
||||
with open(filename_en, 'rb') as file1:
|
||||
ROM_en = file1.read()
|
||||
with open(filename_en, 'rb') as file:
|
||||
ROM_en = file.read()
|
||||
print(len(ROM_en), filename_en)
|
||||
with open(filename_jp, 'rb') as file2:
|
||||
ROM_jp = file2.read()
|
||||
with open(filename_jp, 'rb') as file:
|
||||
ROM_jp = file.read()
|
||||
print(len(ROM_jp), filename_jp)
|
||||
with open(filename_jp_ff4, 'rb') as file:
|
||||
ROM_FF4jp = file.read()
|
||||
print(len(ROM_jp), filename_jp)
|
||||
|
||||
stringlist_headers = ["Address", "ID", "Name"]
|
||||
imglist_headers = stringlist_headers + ["Img", "Name JP", "Img JP"]
|
||||
stringlist_headers = ['Address', 'ID', 'Name']
|
||||
imglist_headers = stringlist_headers + ['Img', 'Name JP', 'Img JP']
|
||||
|
||||
|
||||
class FF5Reader(QMainWindow):
|
||||
|
@ -122,32 +128,32 @@ class FF5Reader(QMainWindow):
|
|||
battle_commands = make_string_img_list(0x201150, 7, 0x60, 0x115800, 5)
|
||||
dialogue = make_string_img_list(0x2013F0, 3, 0x900, start_jp=0x082220, len_jp=2, start_str=0x0, start_jp_str=0x0A0000, indirect=True, large=True, macros_en=const.Dialogue_Macros_EN, macros_jp=const.Dialogue_Macros_JP)
|
||||
|
||||
zone_structure = [("NPC Layer", 2, None),
|
||||
("Name", 1, [z[2] for z in zone_names]),
|
||||
("ShadowFlags", 1, None),
|
||||
("0x04", 1, None),
|
||||
("0x05", 1, None),
|
||||
("Flags 0x06", 1, None),
|
||||
("0x07", 1, None),
|
||||
("Tileset", 1, None),
|
||||
("Tileset2", 2, None),
|
||||
#("0x0A", 1, None),
|
||||
("0x0B", 1, None),
|
||||
("Collision Layer",1, None),
|
||||
("0x0D", 1, None),
|
||||
("0x0E", 1, None),
|
||||
("0x0F", 1, None),
|
||||
("0x10", 1, None),
|
||||
("0x11", 1, None),
|
||||
("0x12", 1, None),
|
||||
("0x13", 1, None),
|
||||
("0x14", 1, None),
|
||||
("0x15", 1, None),
|
||||
("Palette", 1, None),
|
||||
("0x17", 1, None),
|
||||
("0x18", 1, None),
|
||||
("Music", 1, const.BGM_Tracks)]
|
||||
zone_headers = ["Address"] + [z[0] for z in zone_structure]
|
||||
zone_structure = [('NPC Layer', 2, None),
|
||||
('Name', 1, [z[2] for z in zone_names]),
|
||||
('ShadowFlags', 1, None),
|
||||
(hex(4, 2), 1, None),
|
||||
(hex(5, 2), 1, None),
|
||||
('Flags '+hex(6,2),1, None),
|
||||
(hex(7, 2), 1, None),
|
||||
('Tileset', 1, None),
|
||||
('Tileset2', 2, None),
|
||||
#('0x0A', 1, None),
|
||||
(hex(11, 2), 1, None),
|
||||
('Collision Layer',1, None),
|
||||
(hex(13, 2), 1, None),
|
||||
(hex(14, 2), 1, None),
|
||||
(hex(15, 2), 1, None),
|
||||
(hex(16, 2), 1, None),
|
||||
(hex(17, 2), 1, None),
|
||||
(hex(18, 2), 1, None),
|
||||
(hex(19, 2), 1, None),
|
||||
(hex(20, 2), 1, None),
|
||||
(hex(21, 2), 1, None),
|
||||
('Palette', 1, None),
|
||||
(hex(23, 2), 1, None),
|
||||
(hex(24, 2), 1, None),
|
||||
('Music', 1, const.BGM_Tracks)]
|
||||
zone_headers = ['Address'] + [z[0] for z in zone_structure]
|
||||
|
||||
zone_data = []
|
||||
for i in range(const.zone_count):
|
||||
|
@ -160,8 +166,7 @@ class FF5Reader(QMainWindow):
|
|||
offset = 0x0F0000 + (i*2)
|
||||
pointer = 0x0F0000 + int.from_bytes(ROM_en[offset:offset+2],'little')
|
||||
length = int.from_bytes(ROM_en[offset+2:offset+4],'little') - int.from_bytes(ROM_en[offset:offset+2],'little')
|
||||
tileset_data.append(('0x{:02X}'.format(i), '0x{:06X}'.format(offset),
|
||||
'0x{:06X}'.format(pointer), '0x{:04X}'.format(length)))
|
||||
tileset_data.append((hex(i, 2), hex(offset, 6), hex(pointer, 6), hex(length, 4)))
|
||||
|
||||
npc_layers = []
|
||||
offset = 0x0E59C0
|
||||
|
@ -172,28 +177,28 @@ class FF5Reader(QMainWindow):
|
|||
npcs = (next - start) // 7
|
||||
for npc in range(npcs):
|
||||
address = start + (npc*7)
|
||||
npc_layers.append(["0x{0:06X}".format(i), "0x{0:03X}".format(layer)] + parse_struct(ROM_en, address, const.npc_layer_structure))
|
||||
npc_layers.append([hex(i, 6), hex(layer, 3)] + parse_struct(ROM_en, address, const.npc_layer_structure))
|
||||
|
||||
enemy_tile_layouts = []
|
||||
address = 0x10D004
|
||||
for i in range(0x66):
|
||||
offset = address + (i*8)
|
||||
img = QImage(8, 8, QImage.Format_Mono)
|
||||
img.setColorTable(const.mono_palette)
|
||||
for i in range(8):
|
||||
ptr = img.scanLine(i)
|
||||
ptr.setsize(32)
|
||||
ptr[0:1] = ROM_en[offset+i:offset+i+1]
|
||||
pixmap = QPixmap.fromImage(img)
|
||||
enemy_tile_layouts.append(pixmap.scaled(16, 16))
|
||||
#enemy_tile_layouts = []
|
||||
#address = 0x10D004
|
||||
#for i in range(0x66):
|
||||
#offset = address + (i*8)
|
||||
#img = QImage(8, 8, QImage.Format_Mono)
|
||||
#img.setColorTable(const.mono_palette)
|
||||
#for i in range(8):
|
||||
#ptr = img.scanLine(i)
|
||||
#ptr.setsize(32)
|
||||
#ptr[0:1] = ROM_en[offset+i:offset+i+1]
|
||||
#pixmap = QPixmap.fromImage(img)
|
||||
#enemy_tile_layouts.append(pixmap.scaled(16, 16))
|
||||
|
||||
enemy_sprite_data = []
|
||||
enemy_sprite_structure = [
|
||||
("Sprite data offset", 2, None),
|
||||
("Multiple things", 2, None),
|
||||
("Tile Layout ID", 1, enemy_tile_layouts)
|
||||
('Sprite data offset', 2, None),
|
||||
('Multiple things', 2, None),
|
||||
('Tile Layout ID', 1, None)
|
||||
]
|
||||
enemy_sprite_headers = ["Address"]+[i[0] for i in enemy_sprite_structure]+["EN Name","EN Name"]
|
||||
enemy_sprite_headers = ['Address']+[i[0] for i in enemy_sprite_structure]+['EN Name','EN Name']
|
||||
address = 0x14B180
|
||||
for i in range(0x180):
|
||||
enemy_sprite_data.append(parse_struct(ROM_en, address + (i*5), enemy_sprite_structure) + enemy_names[i][2:4])
|
||||
|
@ -201,39 +206,45 @@ class FF5Reader(QMainWindow):
|
|||
self.battle_strips = make_character_battle_sprites(ROM_en)
|
||||
status_strips = make_character_status_sprites(ROM_en)
|
||||
enemy_sprites = make_enemy_sprites(ROM_en)
|
||||
self.battle_strips_ff4 = make_character_battle_sprites_ff4(ROM_FF4jp)
|
||||
|
||||
enemy_sprites_named = [stack_labels(s, d[-2]) for s, d in zip(enemy_sprites, enemy_sprite_data)]
|
||||
|
||||
self.tabwidget = QTabWidget()
|
||||
strings_tab = QTabWidget()
|
||||
structs_tab = QTabWidget()
|
||||
sprites_tab = QTabWidget()
|
||||
self.tabwidget.addTab(strings_tab, "Strings")
|
||||
self.tabwidget.addTab(structs_tab, "Structs")
|
||||
self.tabwidget.addTab(sprites_tab, "Images")
|
||||
self.tabwidget.addTab(strings_tab, 'Strings')
|
||||
self.tabwidget.addTab(structs_tab, 'Structs')
|
||||
self.tabwidget.addTab(sprites_tab, 'Images')
|
||||
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_small, scale=4), "Glyphs (EN)")
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_large, scale=2), "Glyphs (Dialogue EN)")
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_small, scale=4), "Glyphs (JP)")
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_large, scale=2), "Glyphs (Large JP)")
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_kanji, scale=2), "Glyphs (Kanji)")
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips, cols=22, scale=2), "Character Battle Sprites")
|
||||
sprites_tab.addTab(make_pixmap_table(status_strips, cols=22, scale=2), "Status Sprites")
|
||||
sprites_tab.addTab(make_pixmap_table(enemy_sprites, scale=1), "Enemy Sprites")
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_small, scale=4), 'Glyphs (EN)')
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_en_large, scale=2), 'Glyphs (Dialogue EN)')
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_small, scale=4), 'Glyphs (JP)')
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_jp_large, scale=2), 'Glyphs (Large JP)')
|
||||
sprites_tab.addTab(make_pixmap_table(glyph_sprites_kanji, scale=2), 'Glyphs (Kanji)')
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips, cols=22, scale=2), 'Character Battle Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(status_strips, cols=22, scale=2), 'Status Sprites')
|
||||
#sprites_tab.addTab(make_pixmap_table(enemy_sprites, scale=1), 'Enemy Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips_ff4, cols=16, scale=2), 'FF4 Character Battle Sprites')
|
||||
|
||||
structs_tab.addTab(make_table(zone_headers, zone_data, True), "Zones")
|
||||
structs_tab.addTab(make_table(tileset_headers, tileset_data, True), "Tilesets")
|
||||
structs_tab.addTab(make_table(const.npc_layer_headers, npc_layers, True), "NPC Layers")
|
||||
structs_tab.addTab(make_table(enemy_sprite_headers, enemy_sprite_data, True), "Enemy Sprites")
|
||||
|
||||
strings_tab.addTab(make_table(imglist_headers, items, row_labels=False), "Items")
|
||||
strings_tab.addTab(make_table(imglist_headers, magics, row_labels=False), "Magics")
|
||||
strings_tab.addTab(make_table(imglist_headers, more_magics, row_labels=False), "More Magics")
|
||||
strings_tab.addTab(make_table(imglist_headers, enemy_names, row_labels=False), "Enemy Names")
|
||||
strings_tab.addTab(make_table(imglist_headers, character_names, row_labels=False), "Character Names")
|
||||
strings_tab.addTab(make_table(imglist_headers, job_names, row_labels=False), "Job Names")
|
||||
strings_tab.addTab(make_table(imglist_headers, ability_names, row_labels=False), "Ability Names")
|
||||
strings_tab.addTab(make_table(imglist_headers, battle_commands, row_labels=False), "Battle Commands")
|
||||
strings_tab.addTab(make_table(imglist_headers, zone_names, True, scale=1), "Zone Names")
|
||||
strings_tab.addTab(make_table(imglist_headers+['JP address'], dialogue, scale=1), "Dialogue")
|
||||
structs_tab.addTab(make_table(zone_headers, zone_data, True), 'Zones')
|
||||
structs_tab.addTab(make_table(tileset_headers, tileset_data, True), 'Tilesets')
|
||||
structs_tab.addTab(make_table(const.npc_layer_headers, npc_layers, True), 'NPC Layers')
|
||||
structs_tab.addTab(make_table(enemy_sprite_headers, enemy_sprite_data, True), 'Enemy Sprites')
|
||||
|
||||
strings_tab.addTab(make_table(imglist_headers, items, row_labels=False), 'Items')
|
||||
strings_tab.addTab(make_table(imglist_headers, magics, row_labels=False), 'Magics')
|
||||
strings_tab.addTab(make_table(imglist_headers, more_magics, row_labels=False), 'More Magics')
|
||||
strings_tab.addTab(make_table(imglist_headers, enemy_names, row_labels=False), 'Enemy Names')
|
||||
strings_tab.addTab(make_table(imglist_headers, character_names, row_labels=False), 'Character Names')
|
||||
strings_tab.addTab(make_table(imglist_headers, job_names, row_labels=False), 'Job Names')
|
||||
strings_tab.addTab(make_table(imglist_headers, ability_names, row_labels=False), 'Ability Names')
|
||||
strings_tab.addTab(make_table(imglist_headers, battle_commands, row_labels=False), 'Battle Commands')
|
||||
strings_tab.addTab(make_table(imglist_headers, zone_names, True, scale=1), 'Zone Names')
|
||||
strings_tab.addTab(make_table(imglist_headers+['JP address'], dialogue, scale=1), 'Dialogue')
|
||||
|
||||
self.string_decoder = QWidget()
|
||||
self.decoder_input = QLineEdit()
|
||||
|
@ -241,7 +252,7 @@ class FF5Reader(QMainWindow):
|
|||
self.decoder_layout = QVBoxLayout()
|
||||
self.decoder_layout.addWidget(self.decoder_input)
|
||||
self.string_decoder.setLayout(self.decoder_layout)
|
||||
strings_tab.addTab(self.string_decoder, "String Decoder")
|
||||
strings_tab.addTab(self.string_decoder, 'String Decoder')
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.addWidget(self.tabwidget)
|
||||
|
@ -265,8 +276,8 @@ class FF5Reader(QMainWindow):
|
|||
|
||||
|
||||
class Canvas:
|
||||
def __init__(self, rows, columns, color=bg_trans):
|
||||
self.image = QImage(8*rows, 8*columns, QImage.Format_ARGB32_Premultiplied)
|
||||
def __init__(self, cols, rows, color=bg_trans):
|
||||
self.image = QImage(8*cols, 8*rows, QImage.Format_ARGB32_Premultiplied)
|
||||
self.image.fill(color)
|
||||
self.painter = QtGui.QPainter(self.image)
|
||||
self.max_x = 1
|
||||
|
@ -289,14 +300,14 @@ class Canvas:
|
|||
|
||||
|
||||
def parse_struct(rom, offset, structure):
|
||||
out = ["0x{:06X}".format(offset)]
|
||||
out = [hex(offset, 6)]
|
||||
j = 0
|
||||
for z in structure:
|
||||
val = int.from_bytes(rom[offset+j:offset+j+z[1]],'little')
|
||||
if z[2] and val < len(z[2]):
|
||||
out.append(z[2][val])
|
||||
else:
|
||||
out.append("0x{:0{}X}".format(val, z[1]*2))
|
||||
out.append(hex(val, z[1]*2))
|
||||
j += z[1]
|
||||
return out
|
||||
|
||||
|
@ -333,19 +344,41 @@ def make_enemy_sprites(rom):
|
|||
return sprites
|
||||
|
||||
|
||||
def make_battle_strip(rom, palette_address, tile_address, num_tiles):
|
||||
palette = generate_palette(rom, palette_address)
|
||||
# We don't want the background drawn, so we'll make that colour transparent
|
||||
palette[0] = 0
|
||||
battle_strip = Canvas(2, divceil(num_tiles, 2)) # KO sprites are here which means more tiles than FFV
|
||||
for j in range(num_tiles):
|
||||
offset = tile_address+(j*32)
|
||||
battle_strip.draw_pixmap(j%2, j//2, create_tile(rom[offset:offset+32], palette))
|
||||
return battle_strip.pixmap()
|
||||
|
||||
|
||||
def make_character_battle_sprites_ff4(rom):
|
||||
tile_address = 0x0D0000
|
||||
pig_tile_address = 0x0D7000
|
||||
golbez_tile_address = 0x0D7600
|
||||
anna_tile_address = 0x0D7960
|
||||
palette_address = 0x0E7D00
|
||||
golbez_palette_address = 0x0E7EC0
|
||||
anna_palette_address = 0x0E7EE0
|
||||
battle_strips = []
|
||||
for i in range(0, 14*32, 32): # 14 regular characters. Pig, Golbez and Anna follow with different tile spacing and palette order.
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+i, tile_address+(i*64), 64)) # KO sprites are here which means more tiles per strip than FFV
|
||||
battle_strips.append(make_battle_strip(rom, golbez_palette_address, golbez_tile_address, 27))
|
||||
battle_strips.append(make_battle_strip(rom, anna_palette_address, anna_tile_address, 14))
|
||||
for i in range(0, 16*32, 32): # 16 pigs.
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+i, pig_tile_address, 48))
|
||||
return battle_strips
|
||||
|
||||
|
||||
def make_character_battle_sprites(rom):
|
||||
tile_address = 0x120000
|
||||
palette_address = 0x14A3C0
|
||||
battle_strips = []
|
||||
for i in range(0, 110*32, 32):
|
||||
palette = generate_palette(rom, palette_address + i)
|
||||
# We don't want the background drawn, so we'll make that colour transparent
|
||||
palette[0] = 0
|
||||
battle_strip = Canvas(2, 24)
|
||||
for j in range(48):
|
||||
offset = tile_address+(i*48)+(j*32)
|
||||
battle_strip.draw_pixmap(j%2, j//2, create_tile(rom[offset:offset+32], palette))
|
||||
battle_strips.append(battle_strip.pixmap())
|
||||
for i in range(0, (22*5)*32, 32): # 22 jobs 5 characters
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+i, tile_address+(i*48), 48))
|
||||
return battle_strips
|
||||
|
||||
|
||||
|
@ -504,8 +537,8 @@ def make_string_img_list(start, length, num, start_jp=None, len_jp=None, start_s
|
|||
str_jp = ''
|
||||
img_jp = None
|
||||
stringlist.append([
|
||||
"0x{:06X}".format(en), "0x{:0{}X}".format(id, id_digits),
|
||||
str_en, img_en, str_jp, img_jp, "0x{:06X}".format(jp_start)
|
||||
hex(en, 6), hex(id, id_digits),
|
||||
str_en, img_en, str_jp, img_jp, hex(jp_start, 6)
|
||||
])
|
||||
else:
|
||||
for id in range(num):
|
||||
|
@ -517,7 +550,7 @@ def make_string_img_list(start, length, num, start_jp=None, len_jp=None, start_s
|
|||
else:
|
||||
str_en, img_en = make_string_img_small(ROM_en[j1:j1+length])
|
||||
str_jp, img_jp = make_string_img_small(ROM_jp[j2:j2+len_jp], jp=True)
|
||||
stringlist.append(["0x{:06X}".format(j1), "0x{:0{}X}".format(id, id_digits), str_en, img_en, str_jp, img_jp])
|
||||
stringlist.append([hex(j1, 6), hex(id, id_digits), str_en, img_en, str_jp, img_jp])
|
||||
return stringlist
|
||||
|
||||
|
||||
|
@ -533,26 +566,34 @@ def table_size_to_contents(table):
|
|||
|
||||
|
||||
def make_table(headers, items, sortable=False, row_labels=True, scale=2):
|
||||
"""
|
||||
'''
|
||||
Helper function to tabulate 2d lists
|
||||
"""
|
||||
'''
|
||||
cols = len(headers)
|
||||
rows = len(items)
|
||||
rd = hex_length(rows-1)
|
||||
table = QTableWidget(rows, cols)
|
||||
if row_labels:
|
||||
table.setVerticalHeaderLabels(['0x{:0{}X}'.format(v, rd) for v in range(rows)])
|
||||
table.setVerticalHeaderLabels([hex(v, rd) for v in range(rows)])
|
||||
else:
|
||||
table.verticalHeader().setVisible(False)
|
||||
table.setHorizontalHeaderLabels(headers)
|
||||
for row, col, item in [(x,y,items[x][y]) for x in range(rows) for y in range(cols)]:
|
||||
if type(item) == type(QPixmap()):
|
||||
if isinstance(item, QWidget):
|
||||
table.setCellWidget(row, col, item)
|
||||
elif isinstance(item, QPixmap):
|
||||
pix = item.scaled(item.size() * scale)
|
||||
lab = QLabel()
|
||||
lab.setPixmap(item.scaled(item.size() * scale))
|
||||
lab.setPixmap(pix)
|
||||
table.setCellWidget(row, col, lab)
|
||||
elif item is not None:
|
||||
if item.endswith('₁₆'):
|
||||
s = '<tt>{}</tt><sub>16</sub>'.format(item[:-2])
|
||||
lab = QLabel(s)
|
||||
table.setCellWidget(row, col, lab)
|
||||
else:
|
||||
q_item = QTableWidgetItem(item)
|
||||
if item[:2] == "0x":
|
||||
if item.startswith(HEX_PREFIX):
|
||||
q_item.setFont(monofont)
|
||||
table.setItem(row, col, q_item)
|
||||
table_size_to_contents(table)
|
||||
|
@ -567,10 +608,12 @@ def make_pixmap_table(items, cols=16, scale=4):
|
|||
rd = hex_length(rows-1)+1
|
||||
cd = hex_length(cols-1)
|
||||
table = QTableWidget(rows, cols)
|
||||
table.setVerticalHeaderLabels(['0x{:0{}X}'.format(v*cols, rd) for v in range(rows)])
|
||||
table.setHorizontalHeaderLabels(['0x{:0{}X}'.format(v, cd) for v in range(cols)])
|
||||
for i in range(len(items)):
|
||||
item = items[i]
|
||||
table.setVerticalHeaderLabels([hex(v*cols, rd) for v in range(rows)])
|
||||
table.setHorizontalHeaderLabels([hex(v, cd) for v in range(cols)])
|
||||
for i, item in enumerate(items):
|
||||
if isinstance(item, QWidget):
|
||||
table.setCellWidget(i // cols, i % cols, item)
|
||||
elif isinstance(item, QPixmap):
|
||||
lab = QLabel()
|
||||
lab.setPixmap(item.scaled(item.size() * scale))
|
||||
lab.setAlignment(QtCore.Qt.AlignCenter)
|
||||
|
@ -579,6 +622,32 @@ def make_pixmap_table(items, cols=16, scale=4):
|
|||
return table
|
||||
|
||||
|
||||
def stack_labels(*items):
|
||||
w = QWidget()
|
||||
w.setContentsMargins(0, 0, 0, 0)
|
||||
l = QVBoxLayout()
|
||||
l.setAlignment(QtCore.Qt.AlignCenter)
|
||||
l.setSpacing(0)
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
for item in items:
|
||||
lab = QLabel()
|
||||
if isinstance(item, QPixmap):
|
||||
lab.setPixmap(item)
|
||||
else:
|
||||
lab.setText(item.strip())
|
||||
lab.setAlignment(QtCore.Qt.AlignCenter)
|
||||
lab.setMargin(0)
|
||||
l.addWidget(lab)
|
||||
w.setLayout(l)
|
||||
return w
|
||||
|
||||
|
||||
def hex(num, digits):
|
||||
# Consolidate formatting for consistency
|
||||
#return '{:0{}X}₁₆'.format(num, digits)
|
||||
return HEX_PREFIX + '{:0{}X}'.format(num, digits)
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
mainwindow = FF5Reader()
|
||||
|
|
Loading…
Reference in New Issue