desktop-ui: add firmware "scan" function

This allows for firmware to be set from a user selectable firmware directory at the click of a single "Scan" button on the firmware configuration screen.
このコミットが含まれているのは:
Luke Usher 2023-08-22 20:58:20 +01:00
コミット 703e2ea49a
14個のファイルの変更93行の追加21行の削除

ファイルの表示

@ -9,7 +9,7 @@ ColecoVision::ColecoVision() {
manufacturer = "Coleco";
name = "ColecoVision";
firmware.append({"BIOS", "World"});
firmware.append({"BIOS", "World", "990bf1956f10207d8781b619eb74f89b00d921c8d45c95c334c16c8cceca09ad"});
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -13,7 +13,7 @@ FamicomDiskSystem::FamicomDiskSystem() {
manufacturer = "Nintendo";
name = "Famicom Disk System";
firmware.append({"BIOS", "Japan"});
firmware.append({"BIOS", "Japan", "fdc1a76e654feea993fcb38366e05ee5f4eb641f86fe6bebaeefd412e112dd72"});
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -9,7 +9,7 @@ GameGear::GameGear() {
manufacturer = "Sega";
name = "Game Gear";
firmware.append({"BIOS", "World"});
firmware.append({"BIOS", "World", "8c8a21335038285cfa03dc076100c1f0bfadf3e4ff70796f11f3dfaaab60eee2"});
{ InputPort port{"Game Gear"};

ファイルの表示

@ -11,9 +11,9 @@ MasterSystem::MasterSystem() {
manufacturer = "Sega";
name = "Master System";
firmware.append({"BIOS", "US"}); //NTSC-U
firmware.append({"BIOS", "Japan"}); //NTSC-J
firmware.append({"BIOS", "Europe"}); //PAL
firmware.append({"BIOS", "US", "477617917a12a30f9f43844909dc2de6e6a617430f5c9a36306c86414a670d50"}); //NTSC-U
firmware.append({"BIOS", "Japan", "67846e26764bd862f19179294347f7353a4166b62ac4198a5ec32933b7da486e"}); //NTSC-J
firmware.append({"BIOS", "Europe", "477617917a12a30f9f43844909dc2de6e6a617430f5c9a36306c86414a670d50"}); //PAL
{ InputPort port{"Master System"};

ファイルの表示

@ -13,9 +13,9 @@ MegaCD::MegaCD() {
manufacturer = "Sega";
name = "Mega CD";
firmware.append({"BIOS", "US"}); //NTSC-U
firmware.append({"BIOS", "Japan"}); //NTSC-J
firmware.append({"BIOS", "Europe"}); //PAL
firmware.append({"BIOS", "US", "fb477cdbf94c84424c2feca4fe40656d85393fe7b7b401911b45ad2eb991258c"}); //NTSC-U
firmware.append({"BIOS", "Japan", "7133fc2dd2fe5b7d0acd53a5f10f3d00b5d31270239ad20d74ef32393e24af88"}); //NTSC-J
firmware.append({"BIOS", "Europe", "fe608a2a07676a23ab5fd5eee2f53c9e2526d69a28aa16ccd85c0ec42e6933cb"}); //PAL
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -12,7 +12,7 @@ MSX::MSX() {
name = "MSX";
// TODO: Support other region bios versions
firmware.append({"BIOS", "Japan"});
firmware.append({"BIOS", "Japan", "413a2b601a94b3792e054be2439cc77a1819cceadbfa9542f88d51c7480f2ef0"});
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -12,8 +12,8 @@ MSX2::MSX2() {
// TODO: Support other region bios versions
firmware = {};
firmware.append({"MAIN", "Japan"});
firmware.append({"SUB", "Japan"});
firmware.append({"MAIN", "Japan", "0c672d86ead61a97f49a583b88b7c1905da120645cd44f0c9f2baf4f4631e0b1"});
firmware.append({"SUB", "Japan", "6c6f421a10c428d960b7ecc990f99af1c638147f747bddca7b0bf0e2ab738300"});
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -12,9 +12,9 @@ Nintendo64DD::Nintendo64DD() {
manufacturer = "Nintendo";
name = "Nintendo 64DD";
firmware.append({"BIOS", "Japan"});
firmware.append({"BIOS", "US"});
firmware.append({"BIOS", "DEV"});
firmware.append({"BIOS", "Japan", "806400ec0df94b0755de6c5b8249d6b6a9866124c5ddbdac198bde22499bfb8b"});
firmware.append({"BIOS", "US", "e9fec87a45fba02399e88064b9e2f8cf0f2106e351c58279a87f05da5bc984ad"});
firmware.append({"BIOS", "DEV", "9c2962a8b994a29e4cd04b3a6e4ed730a751414655ab6a9799ebf5fc08b79d44"});
for(auto id : range(4)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -12,8 +12,8 @@ PCEngineCD::PCEngineCD() {
manufacturer = "NEC";
name = "PC Engine CD";
firmware.append({"BIOS", "US"}); //NTSC-U
firmware.append({"BIOS", "Japan"}); //NTSC-J
firmware.append({"BIOS", "US", "cadac2725711b3c442bcf237b02f5a5210c96f17625c35fa58f009e0ed39e4db"}); //NTSC-U
firmware.append({"BIOS", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"}); //NTSC-J
allocatePorts();
}

ファイルの表示

@ -14,9 +14,9 @@ PlayStation::PlayStation() {
manufacturer = "Sony";
name = "PlayStation";
firmware.append({"BIOS", "US"}); //NTSC-U
firmware.append({"BIOS", "Japan"}); //NTSC-J
firmware.append({"BIOS", "Europe"}); //PAL
firmware.append({"BIOS", "US", "11052b6499e466bbf0a709b1f9cb6834a9418e66680387912451e971cf8a1fef"}); //NTSC-U
firmware.append({"BIOS", "Japan", "9c0421858e217805f4abe18698afea8d5aa36ff0727eb8484944e00eb5e7eadb"}); //NTSC-J
firmware.append({"BIOS", "Europe", "1faaa18fa820a0225e488d9f086296b8e6c46df739666093987ff7d8fd352c09"}); //PAL
for(auto id : range(2)) {
InputPort port{string{"Controller Port ", 1 + id}};

ファイルの表示

@ -12,7 +12,7 @@ SuperGrafxCD::SuperGrafxCD() {
manufacturer = "NEC";
name = "SuperGrafx CD";
firmware.append({"BIOS", "Japan"}); //NTSC-J
firmware.append({"BIOS", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"}); //NTSC-J
allocatePorts();
}

ファイルの表示

@ -9,6 +9,7 @@ auto FirmwareSettings::construct() -> void {
firmwareList.onActivate([&](auto) { eventAssign(); });
assignButton.setText("Assign").onActivate([&] { eventAssign(); });
clearButton.setText("Clear").onActivate([&] { eventClear(); });
scanButton.setText("Scan").onActivate([&] { eventScan(); });
refresh();
}
@ -99,3 +100,35 @@ auto FirmwareSettings::eventClear() -> void {
}
refresh();
}
auto FirmwareSettings::eventScan() -> void {
for(auto& emulator : emulators) {
for(auto &firmware: emulator->firmware) {
if(!file::exists(firmware.location)) firmware.location = findFirmware(firmware.sha256);
}
}
refresh();
}
auto FirmwareSettings::findFirmware(string hash) -> string {
auto firmwarePath = settings.paths.firmware ?: locate("firmware/");
if(!directory::exists(firmwarePath)) return {};
for(auto& filename : directory::files(firmwarePath)) {
auto location = string{firmwarePath, filename};
if(auto result = fileHashes.find(location)) {
if(!file::exists(location)) continue; //file was removed from disk (or moved)
if(*result == hash) return location;
}
if(file::size(location) >= 10_MiB) continue; //avoid stalling by hashing overly large files
auto digest = Hash::SHA256(file::read(location)).digest();
fileHashes.insert(location, digest);
if(digest != hash) continue;
return location;
}
return {};
}

ファイルの表示

@ -26,6 +26,24 @@ auto PathSettings::construct() -> void {
refresh();
});
firmwareLabel.setText("Firmware").setFont(Font().setBold());
firmwareLayout.setPadding(12_sx, 0);
firmwarePath.setEditable(false);
firmwareAssign.setText("Assign" ELLIPSIS).onActivate([&] {
BrowserDialog dialog;
dialog.setTitle("Select Firmware Path");
dialog.setPath(Path::desktop());
dialog.setAlignment(settingsWindow);
if(auto location = program.selectFolder(dialog)) {
settings.paths.firmware = location;
refresh();
}
});
firmwareReset.setText("Reset").onActivate([&] {
settings.paths.firmware = "";
refresh();
});
savesLabel.setText("Saves").setFont(Font().setBold());
savesLayout.setPadding(12_sx, 0);
savesPath.setEditable(false);
@ -108,6 +126,10 @@ auto PathSettings::refresh() -> void {
name.trimLeft(Path::user(), 1L);
name.prepend("~/");
}
if(name.beginsWith(Path::program())) {
name.trimLeft(Path::program(), 1L);
name.prepend("./");
}
if(name != "/") name.trimRight("/", 1L);
return name;
};
@ -118,6 +140,12 @@ auto PathSettings::refresh() -> void {
homePath.setText(pathname(mia::homeLocation())).setForegroundColor(SystemColor::PlaceholderText);
}
if(settings.paths.firmware) {
firmwarePath.setText(pathname(settings.paths.firmware)).setForegroundColor();
} else {
firmwarePath.setText(pathname(locate("Firmware/"))).setForegroundColor(SystemColor::PlaceholderText);
}
if(settings.paths.saves) {
savesPath.setText(pathname(settings.paths.saves)).setForegroundColor();
} else {

ファイルの表示

@ -73,6 +73,7 @@ struct Settings : Markup::Node {
struct Paths {
string home;
string firmware;
string saves;
string screenshots;
string debugging;
@ -236,13 +237,18 @@ struct FirmwareSettings : VerticalLayout {
auto eventChange() -> void;
auto eventAssign() -> void;
auto eventClear() -> void;
auto eventScan() -> void;
auto findFirmware(string sha256) -> string;
Label firmwareLabel{this, Size{~0, 0}, 5};
TableView firmwareList{this, Size{~0, ~0}};
HorizontalLayout controlLayout{this, Size{~0, 0}};
Button scanButton{&controlLayout, Size{80, 0}};
Canvas spacer{&controlLayout, Size{~0, 0}};
Button assignButton{&controlLayout, Size{80, 0}};
Button clearButton{&controlLayout, Size{80, 0}};
map<string, string> fileHashes;
};
struct PathSettings : VerticalLayout {
@ -254,6 +260,11 @@ struct PathSettings : VerticalLayout {
LineEdit homePath{&homeLayout, Size{~0, 0}};
Button homeAssign{&homeLayout, Size{80, 0}};
Button homeReset{&homeLayout, Size{80, 0}};
Label firmwareLabel{this, Size{~0, 0}, 5};
HorizontalLayout firmwareLayout{this, Size{~0, 0}};
LineEdit firmwarePath{&firmwareLayout, Size{~0, 0}};
Button firmwareAssign{&firmwareLayout, Size{80, 0}};
Button firmwareReset{&firmwareLayout, Size{80, 0}};
Label savesLabel{this, Size{~0, 0}, 5};
HorizontalLayout savesLayout{this, Size{~0, 0}};
LineEdit savesPath{&savesLayout, Size{~0, 0}};