FlashGBX 4.1__py3-none-any.whl → 4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
FlashGBX/FlashGBX_GUI.py CHANGED
@@ -30,6 +30,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
30
30
  TEXT_COLOR = (0, 0, 0, 255)
31
31
 
32
32
  def __init__(self, args):
33
+ sys.excepthook = Util.exception_hook
34
+
33
35
  QtWidgets.QWidget.__init__(self)
34
36
  Util.CONFIG_PATH = args['config_path']
35
37
  Util.APP_PATH = args['app_path']
@@ -241,6 +243,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
241
243
 
242
244
  self.mnuThirdParty = QtWidgets.QMenu("Third Party &Notices")
243
245
  self.mnuThirdParty.addAction("About &Qt", lambda: [ QtWidgets.QMessageBox.aboutQt(None) ])
246
+ self.mnuThirdParty.addAction("About Game &Database", self.AboutGameDB)
244
247
  self.mnuThirdParty.addAction("Licenses", lambda: [ self.OpenPath(Util.APP_PATH + "/res/Third Party Notices.md") ])
245
248
 
246
249
  btnText = "&Options"
@@ -313,7 +316,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
313
316
  self.lblDMGGameNameResult = QtWidgets.QLabel("")
314
317
  rowDMGGameName.addWidget(self.lblDMGGameNameResult)
315
318
  rowDMGGameName.setStretch(0, 9)
316
- rowDMGGameName.setStretch(1, 11)
319
+ rowDMGGameName.setStretch(1, 12)
317
320
  group_layout.addLayout(rowDMGGameName)
318
321
 
319
322
  rowDMGRomTitle = QtWidgets.QHBoxLayout()
@@ -323,7 +326,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
323
326
  self.lblDMGRomTitleResult = QtWidgets.QLabel("")
324
327
  rowDMGRomTitle.addWidget(self.lblDMGRomTitleResult)
325
328
  rowDMGRomTitle.setStretch(0, 9)
326
- rowDMGRomTitle.setStretch(1, 11)
329
+ rowDMGRomTitle.setStretch(1, 12)
327
330
  group_layout.addLayout(rowDMGRomTitle)
328
331
 
329
332
  rowDMGGameCodeRevision = QtWidgets.QHBoxLayout()
@@ -333,7 +336,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
333
336
  self.lblDMGGameCodeRevisionResult = QtWidgets.QLabel("")
334
337
  rowDMGGameCodeRevision.addWidget(self.lblDMGGameCodeRevisionResult)
335
338
  rowDMGGameCodeRevision.setStretch(0, 9)
336
- rowDMGGameCodeRevision.setStretch(1, 11)
339
+ rowDMGGameCodeRevision.setStretch(1, 12)
337
340
  group_layout.addLayout(rowDMGGameCodeRevision)
338
341
 
339
342
  rowDMGHeaderRtc = QtWidgets.QHBoxLayout()
@@ -344,7 +347,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
344
347
  self.lblDMGHeaderRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
345
348
  rowDMGHeaderRtc.addWidget(self.lblDMGHeaderRtcResult)
346
349
  rowDMGHeaderRtc.setStretch(0, 9)
347
- rowDMGHeaderRtc.setStretch(1, 11)
350
+ rowDMGHeaderRtc.setStretch(1, 12)
348
351
  group_layout.addLayout(rowDMGHeaderRtc)
349
352
 
350
353
  rowDMGHeaderBootlogo = QtWidgets.QHBoxLayout()
@@ -354,7 +357,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
354
357
  self.lblDMGHeaderBootlogoResult = QtWidgets.QLabel("")
355
358
  rowDMGHeaderBootlogo.addWidget(self.lblDMGHeaderBootlogoResult)
356
359
  rowDMGHeaderBootlogo.setStretch(0, 9)
357
- rowDMGHeaderBootlogo.setStretch(1, 11)
360
+ rowDMGHeaderBootlogo.setStretch(1, 12)
358
361
  group_layout.addLayout(rowDMGHeaderBootlogo)
359
362
 
360
363
  rowDMGHeaderROMChecksum = QtWidgets.QHBoxLayout()
@@ -364,7 +367,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
364
367
  self.lblDMGHeaderROMChecksumResult = QtWidgets.QLabel("")
365
368
  rowDMGHeaderROMChecksum.addWidget(self.lblDMGHeaderROMChecksumResult)
366
369
  rowDMGHeaderROMChecksum.setStretch(0, 9)
367
- rowDMGHeaderROMChecksum.setStretch(1, 11)
370
+ rowDMGHeaderROMChecksum.setStretch(1, 12)
368
371
  group_layout.addLayout(rowDMGHeaderROMChecksum)
369
372
 
370
373
  rowDMGHeaderROMSize = QtWidgets.QHBoxLayout()
@@ -375,7 +378,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
375
378
  self.cmbDMGHeaderROMSizeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
376
379
  rowDMGHeaderROMSize.addWidget(self.cmbDMGHeaderROMSizeResult)
377
380
  rowDMGHeaderROMSize.setStretch(0, 9)
378
- rowDMGHeaderROMSize.setStretch(1, 11)
381
+ rowDMGHeaderROMSize.setStretch(1, 12)
379
382
  group_layout.addLayout(rowDMGHeaderROMSize)
380
383
 
381
384
  rowDMGHeaderSaveType = QtWidgets.QHBoxLayout()
@@ -386,7 +389,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
386
389
  self.cmbDMGHeaderSaveTypeResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
387
390
  rowDMGHeaderSaveType.addWidget(self.cmbDMGHeaderSaveTypeResult)
388
391
  rowDMGHeaderSaveType.setStretch(0, 9)
389
- rowDMGHeaderSaveType.setStretch(1, 11)
392
+ rowDMGHeaderSaveType.setStretch(1, 12)
390
393
  group_layout.addLayout(rowDMGHeaderSaveType)
391
394
 
392
395
  rowDMGHeaderMapper = QtWidgets.QHBoxLayout()
@@ -397,7 +400,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
397
400
  self.cmbDMGHeaderMapperResult.view().setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
398
401
  rowDMGHeaderMapper.addWidget(self.cmbDMGHeaderMapperResult)
399
402
  rowDMGHeaderMapper.setStretch(0, 9)
400
- rowDMGHeaderMapper.setStretch(1, 11)
403
+ rowDMGHeaderMapper.setStretch(1, 12)
401
404
  group_layout.addLayout(rowDMGHeaderMapper)
402
405
 
403
406
  rowDMGCartridgeType = QtWidgets.QHBoxLayout()
@@ -427,7 +430,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
427
430
  self.lblAGBGameNameResult = QtWidgets.QLabel("")
428
431
  rowAGBGameName.addWidget(self.lblAGBGameNameResult)
429
432
  rowAGBGameName.setStretch(0, 9)
430
- rowAGBGameName.setStretch(1, 11)
433
+ rowAGBGameName.setStretch(1, 12)
431
434
  group_layout.addLayout(rowAGBGameName)
432
435
 
433
436
  rowAGBRomTitle = QtWidgets.QHBoxLayout()
@@ -437,7 +440,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
437
440
  self.lblAGBRomTitleResult = QtWidgets.QLabel("")
438
441
  rowAGBRomTitle.addWidget(self.lblAGBRomTitleResult)
439
442
  rowAGBRomTitle.setStretch(0, 9)
440
- rowAGBRomTitle.setStretch(1, 11)
443
+ rowAGBRomTitle.setStretch(1, 12)
441
444
  group_layout.addLayout(rowAGBRomTitle)
442
445
 
443
446
  rowAGBHeaderGameCodeRevision = QtWidgets.QHBoxLayout()
@@ -447,7 +450,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
447
450
  self.lblAGBHeaderGameCodeRevisionResult = QtWidgets.QLabel("")
448
451
  rowAGBHeaderGameCodeRevision.addWidget(self.lblAGBHeaderGameCodeRevisionResult)
449
452
  rowAGBHeaderGameCodeRevision.setStretch(0, 9)
450
- rowAGBHeaderGameCodeRevision.setStretch(1, 11)
453
+ rowAGBHeaderGameCodeRevision.setStretch(1, 12)
451
454
  group_layout.addLayout(rowAGBHeaderGameCodeRevision)
452
455
 
453
456
  rowAGBGpioRtc = QtWidgets.QHBoxLayout()
@@ -458,7 +461,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
458
461
  self.lblAGBGpioRtcResult.mousePressEvent = lambda event: [ self.EditRTC(event) ]
459
462
  rowAGBGpioRtc.addWidget(self.lblAGBGpioRtcResult)
460
463
  rowAGBGpioRtc.setStretch(0, 9)
461
- rowAGBGpioRtc.setStretch(1, 11)
464
+ rowAGBGpioRtc.setStretch(1, 12)
462
465
  group_layout.addLayout(rowAGBGpioRtc)
463
466
 
464
467
  rowAGBHeaderBootlogo = QtWidgets.QHBoxLayout()
@@ -468,7 +471,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
468
471
  self.lblAGBHeaderBootlogoResult = QtWidgets.QLabel("")
469
472
  rowAGBHeaderBootlogo.addWidget(self.lblAGBHeaderBootlogoResult)
470
473
  rowAGBHeaderBootlogo.setStretch(0, 9)
471
- rowAGBHeaderBootlogo.setStretch(1, 11)
474
+ rowAGBHeaderBootlogo.setStretch(1, 12)
472
475
  group_layout.addLayout(rowAGBHeaderBootlogo)
473
476
 
474
477
  rowAGBHeaderChecksum = QtWidgets.QHBoxLayout()
@@ -478,7 +481,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
478
481
  self.lblAGBHeaderChecksumResult = QtWidgets.QLabel("")
479
482
  rowAGBHeaderChecksum.addWidget(self.lblAGBHeaderChecksumResult)
480
483
  rowAGBHeaderChecksum.setStretch(0, 9)
481
- rowAGBHeaderChecksum.setStretch(1, 11)
484
+ rowAGBHeaderChecksum.setStretch(1, 12)
482
485
  group_layout.addLayout(rowAGBHeaderChecksum)
483
486
 
484
487
  rowAGBHeaderROMChecksum = QtWidgets.QHBoxLayout()
@@ -488,7 +491,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
488
491
  self.lblAGBHeaderROMChecksumResult = QtWidgets.QLabel("")
489
492
  rowAGBHeaderROMChecksum.addWidget(self.lblAGBHeaderROMChecksumResult)
490
493
  rowAGBHeaderROMChecksum.setStretch(0, 9)
491
- rowAGBHeaderROMChecksum.setStretch(1, 11)
494
+ rowAGBHeaderROMChecksum.setStretch(1, 12)
492
495
  group_layout.addLayout(rowAGBHeaderROMChecksum)
493
496
 
494
497
  rowAGBHeaderROMSize = QtWidgets.QHBoxLayout()
@@ -501,7 +504,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
501
504
  self.cmbAGBHeaderROMSizeResult.setCurrentIndex(self.cmbAGBHeaderROMSizeResult.count() - 1)
502
505
  rowAGBHeaderROMSize.addWidget(self.cmbAGBHeaderROMSizeResult)
503
506
  rowAGBHeaderROMSize.setStretch(0, 9)
504
- rowAGBHeaderROMSize.setStretch(1, 11)
507
+ rowAGBHeaderROMSize.setStretch(1, 12)
505
508
  group_layout.addLayout(rowAGBHeaderROMSize)
506
509
 
507
510
  rowAGBHeaderSaveType = QtWidgets.QHBoxLayout()
@@ -514,7 +517,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
514
517
  self.cmbAGBSaveTypeResult.setCurrentIndex(self.cmbAGBSaveTypeResult.count() - 1)
515
518
  rowAGBHeaderSaveType.addWidget(self.cmbAGBSaveTypeResult)
516
519
  rowAGBHeaderSaveType.setStretch(0, 9)
517
- rowAGBHeaderSaveType.setStretch(1, 11)
520
+ rowAGBHeaderSaveType.setStretch(1, 12)
518
521
  group_layout.addLayout(rowAGBHeaderSaveType)
519
522
 
520
523
  rowAGBCartridgeType = QtWidgets.QHBoxLayout()
@@ -709,7 +712,13 @@ class FlashGBX_GUI(QtWidgets.QWidget):
709
712
  msg = "This software is being developed by Lesserkuma as a hobby project. There is no affiliation with Nintendo or any other company. This software is provided as-is and the developer is not responsible for any damage that is caused by the use of it. Use at your own risk!<br><br>"
710
713
  msg += f"© 2020–{datetime.datetime.now().year} Lesserkuma<br>"
711
714
  msg += "• Website: <a href=\"https://github.com/lesserkuma/FlashGBX\">https://github.com/lesserkuma/FlashGBX</a><br><br>"
712
- msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, inYourBackline, iyatemu, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
715
+ msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, inYourBackline, iyatemu, Jayro, Jenetrix, JFox, joyrider3774, jrharbort, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
716
+ QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
717
+
718
+ def AboutGameDB(self):
719
+ msg = f"{APPNAME} uses a game database that is based on the ongoing efforts of the No-Intro project. Visit <a href=\"https://no-intro.org/\">https://no-intro.org/</a> for more information.<br><br>"
720
+ msg += f"No-Intro databases referenced for this version of {APPNAME}:<br>"
721
+ msg += "• Nintendo - Game Boy (20241003-140822)<br>• Nintendo - Game Boy Advance (20241102-092521)<br>• Nintendo - Game Boy Advance (Video) (20241021-195439)<br>• Nintendo - Game Boy Color (20241105-004534)" # No-Intro DBs
713
722
  QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
714
723
 
715
724
  def OpenPath(self, path=None):
@@ -733,26 +742,19 @@ class FlashGBX_GUI(QtWidgets.QWidget):
733
742
  if isinstance(event, QtGui.QMouseEvent):
734
743
  if event.button() in (QtCore.Qt.MouseButton.MiddleButton, QtCore.Qt.MouseButton.RightButton): return
735
744
 
745
+ device = False
736
746
  try:
737
- Util.dprint("{:s} version: {:s} ({:d})".format(Util.APPNAME, Util.VERSION_PEP440, Util.VERSION_TIMESTAMP))
738
- Util.dprint("Platform: {:s}".format(platform.platform()))
739
- if self.CONN is not None:
740
- Util.dprint("Connected device: {:s}".format(self.CONN.GetFullNameExtended(more=True)))
741
- else:
742
- Util.dprint("No device connected")
743
- Util.dprint("Now writing debug log file")
747
+ device = self.CONN.GetFullNameExtended(more=True)
744
748
  except:
745
749
  pass
750
+
751
+ Util.write_debug_log(device)
746
752
  try:
747
- fn = Util.CONFIG_PATH + "/debug.log"
748
- with open(fn, "wb") as f:
749
- f.write("\n".join(Util.DEBUG_LOG).encode("UTF-8-SIG"))
750
- print("debug.log written")
751
753
  if open_log is True:
754
+ fn = Util.CONFIG_PATH + "/debug.log"
752
755
  self.OpenPath(fn)
753
- return True
754
756
  except:
755
- return False
757
+ pass
756
758
 
757
759
  def ConnectDevice(self):
758
760
  if self.CONN is not None:
@@ -865,6 +867,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
865
867
  if dev.FirmwareUpdateAvailable():
866
868
  dontShowAgain = str(self.SETTINGS.value("SkipFirmwareUpdate", default="disabled")).lower() == "enabled"
867
869
  if not dontShowAgain or dev.FW_UPDATE_REQ:
870
+ cb = None
868
871
  if dev.FW_UPDATE_REQ is True:
869
872
  text = "A firmware update for your {:s} device is required to use this software. Do you want to update now?".format(dev.GetFullName())
870
873
  msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=text, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, defaultButton=QtWidgets.QMessageBox.Yes)
@@ -882,8 +885,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
882
885
  if not Util.DEBUG:
883
886
  self.DisconnectDevice()
884
887
  else:
885
- dontShowAgain = cb.isChecked()
886
- if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
888
+ if cb is not None:
889
+ dontShowAgain = cb.isChecked()
890
+ if dontShowAgain: self.SETTINGS.setValue("SkipFirmwareUpdate", "enabled")
887
891
  if answer == QtWidgets.QMessageBox.Yes:
888
892
  self.ShowFirmwareUpdateWindow()
889
893
 
@@ -892,8 +896,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
892
896
  if not Util.DEBUG:
893
897
  self.DisconnectDevice()
894
898
  QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok)
899
+
900
+ if dev.IsUnregistered():
901
+ try:
902
+ text = dev.GetRegisterInformation()
903
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok)
904
+ except:
905
+ pass
895
906
 
896
907
  return True
908
+
897
909
  return False
898
910
 
899
911
  def FindDevices(self, connectToFirst=False, port=None, mode=None, firstRun=False):
@@ -926,8 +938,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
926
938
  msg = ret[i][1]
927
939
  if msg in messages: # don’t show the same message twice
928
940
  continue
929
- else:
930
- last_msg = msg
941
+ #else:
942
+ # last_msg = msg
931
943
  if status == 3:
932
944
  messages.append(msg)
933
945
  self.CONN = None
@@ -939,7 +951,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
939
951
  if dev.IsConnected():
940
952
  self.DEVICES[dev.GetFullNameExtended()] = dev
941
953
  if dev.GetPort() in ports: break
942
-
954
+
943
955
  for dev in self.DEVICES.values():
944
956
  dev.Close()
945
957
 
@@ -952,7 +964,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
952
964
  msg += message + "\n\n"
953
965
  QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg[:-2], QtWidgets.QMessageBox.Ok)
954
966
  elif not firstRun:
955
- QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="No compatible devices found. Please ensure the device is connected properly.\n\nTroubleshooting advice:\n- Reconnect the device, try different USB ports/cables, avoid passive USB hubs\n- Use a USB data cable (battery charging cables may not work)\n- Check if the operating system detects the device (if not, reboot your machine)\n- Ensure your user account has permissions to use the device\n- Refer to the device compatibility list on the <a href=\"https://github.com/lesserkuma/FlashGBX/#compatible-cartridge-readerwriter-hardware\">GitHub page</a>".replace("\n", "<br>"), standardButtons=QtWidgets.QMessageBox.Ok).exec()
967
+ QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="No compatible devices found. Please ensure the device is connected properly.\n\nTroubleshooting advice:\n- Reconnect the device, try different USB ports/cables, avoid passive USB hubs\n- Use a USB data cable (battery charging cables may not work)\n- Check if the operating system detects the device (if not, reboot your machine)\n- Ensure your user account has permissions to use the device\n- Refer to the device compatibility list on the <a href=\"https://github.com/lesserkuma/FlashGBX/#compatible-cartridge-readerwriter-hardware\">GitHub page</a>\n- Update the firmware manually through Options → Tools → Firmware Updater".replace("\n", "<br>"), standardButtons=QtWidgets.QMessageBox.Ok).exec()
956
968
 
957
969
  self.lblDevice.setText("No devices found.")
958
970
  self.lblDevice.setStyleSheet("")
@@ -1073,7 +1085,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1073
1085
  else:
1074
1086
  msg += " This may indicate a bad dump, however this can be normal for some reproduction cartridges, unlicensed games, prototypes, patched games and intentional overdumps. You can also try to change the read mode in the options."
1075
1087
  if self.CONN.GetMode() == "DMG" and self.cmbDMGHeaderMapperResult.currentText() == "MBC1":
1076
- msg += "\n\nIf this is a NP GB-Memory Cartridge, please use the “Retry as G-MMC1” button."
1088
+ msg += "\n\nIf this is a NP GB-Memory Cartridge, try the “Retry as G-MMC1” option."
1077
1089
  button_gmmc1 = msgbox.addButton(" Retry as G-MMC1 ", QtWidgets.QMessageBox.ActionRole)
1078
1090
  msgbox.setText(msg + msg_te)
1079
1091
  msgbox.setIcon(QtWidgets.QMessageBox.Warning)
@@ -1237,6 +1249,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1237
1249
  self.CONN.INFO["dump_info"]["batteryless_sram"] = temp3
1238
1250
  else:
1239
1251
  self.ReadCartridge(resetStatus=False)
1252
+
1253
+ elif self.CONN.INFO["last_action"] == 6: # Detect Cartridge
1254
+ self.lblStatus4a.setText("Ready.")
1255
+ self.CONN.INFO["last_action"] = 0
1256
+ self.FinishDetectCartridge(self.CONN.INFO["detect_cart"])
1240
1257
 
1241
1258
  else:
1242
1259
  self.lblStatus4a.setText("Ready.")
@@ -1368,11 +1385,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1368
1385
  return
1369
1386
 
1370
1387
  if cart_type == 0:
1371
- cart_type = self.DetectCartridge(canSkipMessage=True)
1388
+ if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
1389
+ if self.STATUS["detected_cart_type"] == "":
1390
+ self.STATUS["detected_cart_type"] = "WAITING_FLASH"
1391
+ self.STATUS["detect_cartridge_args"] = { "dpath":path }
1392
+ self.STATUS["can_skip_message"] = True
1393
+ self.DetectCartridge(checkSaveType=False)
1394
+ return
1395
+ cart_type = self.STATUS["detected_cart_type"]
1396
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
1397
+
1372
1398
  if cart_type is False: # clicked Cancel button
1373
1399
  return
1374
1400
  elif cart_type is None or cart_type == 0:
1375
- QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge type could not be auto-detected.", QtWidgets.QMessageBox.Ok)
1401
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
1376
1402
  return
1377
1403
 
1378
1404
  if self.CONN.GetMode() == "DMG":
@@ -1380,6 +1406,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1380
1406
  elif self.CONN.GetMode() == "AGB":
1381
1407
  self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
1382
1408
 
1409
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
1410
+
1383
1411
  if self.CONN.GetMode() == "DMG":
1384
1412
  self.SetDMGMapperResult(carts[cart_type])
1385
1413
  mbc = Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex())
@@ -1460,7 +1488,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1460
1488
  if not Util.compare_mbc(hdr["mapper_raw"], mbc):
1461
1489
  mbc1 = Util.get_mbc_name(mbc)
1462
1490
  mbc2 = Util.get_mbc_name(hdr["mapper_raw"])
1463
- compatible_mbc = [ "None", "MBC2", "MBC3", "MBC30", "MBC5", "MBC7", "MAC-GBD", "G-MMC1", "HuC-1", "HuC-3" ]
1491
+ compatible_mbc = [ "None", "MBC2", "MBC3", "MBC30", "MBC5", "MBC7", "MAC-GBD", "G-MMC1", "HuC-1", "HuC-3", "Unlicensed MBCX Mapper" ]
1464
1492
  if (mbc2 == "None") or (mbc1 == "G-MMC1" and mbc2 == "MBC1") or (mbc2 == "G-MMC1" and mbc1 == "MBC1"):
1465
1493
  pass
1466
1494
  elif mbc2 != "None" and not (mbc1 in compatible_mbc and mbc2 in compatible_mbc):
@@ -1633,14 +1661,25 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1633
1661
  return
1634
1662
  cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
1635
1663
  if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
1636
- cart_type = self.DetectCartridge()
1664
+ if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
1665
+ if self.STATUS["detected_cart_type"] == "":
1666
+ self.STATUS["detected_cart_type"] = "WAITING_SAVE_READ"
1667
+ self.STATUS["detect_cartridge_args"] = { "dpath":path }
1668
+ self.STATUS["can_skip_message"] = True
1669
+ self.DetectCartridge(checkSaveType=True)
1670
+ return
1671
+ cart_type = self.STATUS["detected_cart_type"]
1672
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
1673
+
1637
1674
  if cart_type is False: # clicked Cancel button
1638
1675
  return
1639
1676
  elif cart_type is None or cart_type == 0:
1640
- QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge type could not be auto-detected.", QtWidgets.QMessageBox.Ok)
1677
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
1641
1678
  return
1642
1679
  self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
1643
1680
 
1681
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
1682
+
1644
1683
  if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
1645
1684
  detected = self.CONN.INFO["dump_info"]["batteryless_sram"]
1646
1685
  else:
@@ -1671,10 +1710,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1671
1710
  self.STATUS["last_path"] = path
1672
1711
  self.STATUS["args"] = args
1673
1712
 
1674
- def WriteRAM(self, dpath="", erase=False, test=False):
1713
+ def WriteRAM(self, dpath="", erase=False, test=False, skip_warning=False):
1675
1714
  if not self.CheckDeviceAlive(): return
1676
1715
  mode = self.CONN.GetMode()
1677
1716
 
1717
+ if erase is True: dpath = ""
1718
+
1678
1719
  if dpath == "":
1679
1720
  path = Util.GenerateFileName(mode=mode, header=self.CONN.INFO, settings=self.SETTINGS)
1680
1721
  path = os.path.splitext(path)[0]
@@ -1709,14 +1750,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
1709
1750
 
1710
1751
  filesize = 0
1711
1752
  if dpath != "":
1712
- text = "The following save data file will now be written to the cartridge:\n" + dpath
1713
- answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
1714
- if answer == QtWidgets.QMessageBox.Cancel: return
1753
+ if not skip_warning:
1754
+ text = "The following save data file will now be written to the cartridge:\n" + dpath
1755
+ answer = QtWidgets.QMessageBox.question(self, "{:s} {:s}".format(APPNAME, VERSION), text, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
1756
+ if answer == QtWidgets.QMessageBox.Cancel: return
1715
1757
  path = dpath
1716
1758
  self.SETTINGS.setValue(setting_name, os.path.dirname(path))
1717
1759
  elif erase:
1718
- answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The save data on your cartridge will now be erased.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
1719
- if answer == QtWidgets.QMessageBox.Cancel: return
1760
+ if not skip_warning:
1761
+ answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The save data on your cartridge will now be erased.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
1762
+ if answer == QtWidgets.QMessageBox.Cancel: return
1720
1763
  elif test:
1721
1764
  path = None
1722
1765
  if self.CONN.GetFWBuildDate() == "": # Legacy Mode
@@ -2013,14 +2056,25 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2013
2056
  return
2014
2057
  cart_type = self.cmbAGBCartridgeTypeResult.currentIndex()
2015
2058
  if cart_type == 0 or ("dump_info" not in self.CONN.INFO or "batteryless_sram" not in self.CONN.INFO["dump_info"]):
2016
- cart_type = self.DetectCartridge()
2059
+ if "detected_cart_type" not in self.STATUS: self.STATUS["detected_cart_type"] = ""
2060
+ if self.STATUS["detected_cart_type"] == "":
2061
+ self.STATUS["detected_cart_type"] = "WAITING_SAVE_WRITE"
2062
+ self.STATUS["detect_cartridge_args"] = { "dpath":path, "erase":erase }
2063
+ self.STATUS["can_skip_message"] = True
2064
+ self.DetectCartridge(checkSaveType=True)
2065
+ return
2066
+ cart_type = self.STATUS["detected_cart_type"]
2067
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
2068
+
2017
2069
  if cart_type is False: # clicked Cancel button
2018
2070
  return
2019
2071
  elif cart_type is None or cart_type == 0:
2020
- QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge type could not be auto-detected.", QtWidgets.QMessageBox.Ok)
2072
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "A compatible flash cartridge profile could not be auto-detected.", QtWidgets.QMessageBox.Ok)
2021
2073
  return
2022
2074
  self.cmbAGBCartridgeTypeResult.setCurrentIndex(cart_type)
2023
2075
 
2076
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
2077
+
2024
2078
  if "dump_info" in self.CONN.INFO and "batteryless_sram" in self.CONN.INFO["dump_info"]:
2025
2079
  detected = self.CONN.INFO["dump_info"]["batteryless_sram"]
2026
2080
  else:
@@ -2080,6 +2134,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2080
2134
  except:
2081
2135
  pass
2082
2136
 
2137
+ intro_msg = ""
2083
2138
  if detected is not False:
2084
2139
  try:
2085
2140
  loc_index = locs.index(detected["bl_offset"])
@@ -2147,7 +2202,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2147
2202
 
2148
2203
  if self.CONN.GetMode() == "DMG":
2149
2204
  mbc = Util.get_mbc_name(Util.ConvertMapperTypeToMapper(self.cmbDMGHeaderMapperResult.currentIndex()))
2150
- if mbc in ("MBC3", "MBC30"):
2205
+ if mbc in ("MBC3", "MBC30", "Unlicensed MBCX Mapper"):
2151
2206
  dlg_args = {
2152
2207
  "title":"MBC3/MBC30 Real Time Clock Editor",
2153
2208
  "intro":"Enter the number of days, hours, minutes and seconds that passed since the RTC initially started.\n\nPlease note that all values are internal values. The game may use these only as a relative reference.",
@@ -2372,10 +2427,16 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2372
2427
 
2373
2428
  if not self.CheckDeviceAlive(setMode=setTo): return
2374
2429
 
2375
- if self.optDMG.isChecked() and (mode == "AGB" or mode == None):
2376
- self.CONN.SetMode("DMG")
2377
- elif self.optAGB.isChecked() and (mode == "DMG" or mode == None):
2378
- self.CONN.SetMode("AGB")
2430
+ try:
2431
+ if self.optDMG.isChecked() and (mode == "AGB" or mode == None):
2432
+ self.CONN.SetMode("DMG")
2433
+ elif self.optAGB.isChecked() and (mode == "DMG" or mode == None):
2434
+ self.CONN.SetMode("AGB")
2435
+ except BrokenPipeError:
2436
+ msg = "Failed to turn on the cartridge power.\n\nAs a workaround, try to disable the \"Automatic cartridge power off\" setting and then hotplug the cartridge after clicking \"Refresh\"."
2437
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
2438
+ self.DisconnectDevice()
2439
+ return False
2379
2440
 
2380
2441
  ok = self.ReadCartridge()
2381
2442
  qt_app.processEvents()
@@ -2415,7 +2476,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2415
2476
  return False
2416
2477
 
2417
2478
  if self.CONN.CheckROMStable() is False and resetStatus:
2418
- QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge connection is unstable!\nPlease clean the cartridge pins, carefully realign the cartridge and then try again.", QtWidgets.QMessageBox.Ok)
2479
+ try:
2480
+ if data != bytearray(data[0] * len(data)):
2481
+ QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge connection is unstable!\nPlease clean the cartridge pins, carefully realign the cartridge and then try again.", QtWidgets.QMessageBox.Ok)
2482
+ except:
2483
+ pass
2419
2484
 
2420
2485
  if self.CONN.GetMode() == "DMG":
2421
2486
  self.cmbDMGHeaderMapperResult.clear()
@@ -2440,7 +2505,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2440
2505
  self.lblDMGGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
2441
2506
  temp = data["db"]["gn"]
2442
2507
  self.lblDMGGameNameResult.setText(temp)
2443
- while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() > 200:
2508
+ while self.lblDMGGameNameResult.fontMetrics().boundingRect(self.lblDMGGameNameResult.text()).width() > 240:
2444
2509
  temp = temp[:-1]
2445
2510
  self.lblDMGGameNameResult.setText(temp + "…")
2446
2511
  if temp != data["db"]["gn"]:
@@ -2562,7 +2627,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2562
2627
  self.lblAGBHeaderGameCodeRevisionResult.setText("{:s}-{:s}".format(data["db"]["gc"], str(data["version"])))
2563
2628
  temp = data["db"]["gn"]
2564
2629
  self.lblAGBGameNameResult.setText(temp)
2565
- while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() > 200:
2630
+ while self.lblAGBGameNameResult.fontMetrics().boundingRect(self.lblAGBGameNameResult.text()).width() > 240:
2566
2631
  temp = temp[:-1]
2567
2632
  self.lblAGBGameNameResult.setText(temp + "…")
2568
2633
  if temp != data["db"]["gn"]:
@@ -2673,13 +2738,12 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2673
2738
  self.btnRestoreRAM.setEnabled(True)
2674
2739
  self.btnHeaderRefresh.setFocus()
2675
2740
  self.SetProgressBars(min=0, max=100, value=0)
2676
- self.lblStatus4a.setText("Ready.")
2677
2741
  qt_app.processEvents()
2678
2742
 
2679
2743
  if data['game_title'][:11] == "YJencrypted" and resetStatus:
2680
2744
  QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "This cartridge may be protected against reading or writing a ROM. If you don’t want to risk this cartridge to render itself unusable, please do not try to write a new ROM to it.", QtWidgets.QMessageBox.Ok)
2681
2745
 
2682
- def DetectCartridge(self, canSkipMessage=False):
2746
+ def DetectCartridge(self, checkSaveType=True):
2683
2747
  if not self.CheckDeviceAlive(): return
2684
2748
  if not self.CONN.CheckROMStable():
2685
2749
  answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "The cartridge connection is unstable!\nPlease clean the cartridge pins, carefully realign the cartridge for best results.\n\nContinue anyway?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
@@ -2695,12 +2759,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2695
2759
  self.lblStatus2aResult.setText("–")
2696
2760
  self.lblStatus3aResult.setText("–")
2697
2761
  self.lblStatus4aResult.setText("")
2698
- self.lblStatus4a.setText("Analyzing Cartridge...")
2762
+ # self.lblStatus4a.setText("Analyzing Cartridge...")
2699
2763
  self.SetProgressBars(min=0, max=0, value=1)
2700
2764
  qt_app.processEvents()
2701
2765
 
2766
+ if "can_skip_message" not in self.STATUS: self.STATUS["can_skip_message"] = False
2767
+ limitVoltage = str(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled")).lower() == "enabled"
2768
+ self.CONN.DetectCartridge(fncSetProgress=self.PROGRESS.SetProgress, args={"limitVoltage":limitVoltage, "checkSaveType":checkSaveType})
2769
+
2770
+ def FinishDetectCartridge(self, ret):
2771
+ self.lblStatus1aResult.setText("–")
2772
+ self.lblStatus2aResult.setText("–")
2773
+ self.lblStatus3aResult.setText("–")
2774
+
2702
2775
  limitVoltage = str(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled")).lower() == "enabled"
2703
- ret = self.CONN.DetectCartridge(limitVoltage=limitVoltage, checkSaveType=not canSkipMessage)
2704
2776
  if ret is False:
2705
2777
  QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "An error occured while trying to analyze the cartridge and you may need to physically reconnect the device.\n\nThis cartridge may not be auto-detectable, please select the cartridge type manually.", QtWidgets.QMessageBox.Ok)
2706
2778
  self.DisconnectDevice()
@@ -2709,7 +2781,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2709
2781
  (header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret
2710
2782
 
2711
2783
  # Save Type
2712
- if not canSkipMessage:
2784
+ if not self.STATUS["can_skip_message"]:
2713
2785
  try:
2714
2786
  if save_type is not None and save_type is not False:
2715
2787
  if self.CONN.GetMode() == "DMG":
@@ -2728,6 +2800,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2728
2800
  supp_cart_types = self.CONN.GetSupportedCartridgesDMG()
2729
2801
  elif self.CONN.GetMode() == "AGB":
2730
2802
  supp_cart_types = self.CONN.GetSupportedCartridgesAGB()
2803
+ else:
2804
+ raise NotImplementedError
2731
2805
  except Exception as e:
2732
2806
  msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text="An unknown error occured. Please try again.\n\n" + str(e), standardButtons=QtWidgets.QMessageBox.Ok)
2733
2807
  msgbox.exec()
@@ -2761,7 +2835,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2761
2835
  # Save Type
2762
2836
  msg_save_type_s = ""
2763
2837
  temp = ""
2764
- if not canSkipMessage and save_type is not False and save_type is not None:
2838
+ if not self.STATUS["can_skip_message"] and save_type is not False and save_type is not None:
2765
2839
  if save_chip is not None:
2766
2840
  temp = "{:s} ({:s})".format(Util.AGB_Header_Save_Types[save_type], save_chip)
2767
2841
  else:
@@ -2909,7 +2983,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2909
2983
  msg = "The following cartridge configuration was detected:<br><br>"
2910
2984
  if found_supported:
2911
2985
  dontShowAgain = str(self.SETTINGS.value("SkipAutodetectMessage", default="disabled")).lower() == "enabled"
2912
- if not dontShowAgain or not canSkipMessage:
2986
+ if not dontShowAgain or not self.STATUS["can_skip_message"]:
2913
2987
  temp = "{:s}{:s}{:s}{:s}{:s}{:s}".format(msg, msg_flash_size_s, msg_save_type_s, msg_flash_mapper_s, msg_cart_type_s, msg_gbmem)
2914
2988
  temp = temp[:-4]
2915
2989
  msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=temp)
@@ -2919,7 +2993,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2919
2993
  button_cancel = None
2920
2994
  msgbox.setDefaultButton(button_ok)
2921
2995
  cb = QtWidgets.QCheckBox("Always skip this message", checked=False)
2922
- if canSkipMessage:
2996
+ if self.STATUS["can_skip_message"]:
2923
2997
  button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
2924
2998
  msgbox.setEscapeButton(button_cancel)
2925
2999
  msgbox.setCheckBox(cb)
@@ -2928,7 +3002,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2928
3002
 
2929
3003
  msgbox.exec()
2930
3004
  dontShowAgain = cb.isChecked()
2931
- if dontShowAgain and canSkipMessage: self.SETTINGS.setValue("SkipAutodetectMessage", "enabled")
3005
+ if dontShowAgain and self.STATUS["can_skip_message"]: self.SETTINGS.setValue("SkipAutodetectMessage", "enabled")
2932
3006
 
2933
3007
  if msgbox.clickedButton() == button_details:
2934
3008
  show_details = True
@@ -2943,7 +3017,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2943
3017
  self.btnHeaderRefresh.setFocus()
2944
3018
  self.SetProgressBars(min=0, max=100, value=0)
2945
3019
  self.lblStatus4a.setText("Ready.")
2946
- return False
3020
+ self.STATUS["can_skip_message"] = False
3021
+ if "detected_cart_type" in self.STATUS: del(self.STATUS["detected_cart_type"])
3022
+ return
2947
3023
 
2948
3024
  if not found_supported or show_details is True:
2949
3025
  msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION))
@@ -2969,7 +3045,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2969
3045
  if answer == QtWidgets.QMessageBox.Yes:
2970
3046
  self.SETTINGS.setValue("AutoDetectLimitVoltage", "disabled")
2971
3047
  self.mnuConfig.actions()[4].setChecked(False)
2972
- return self.DetectCartridge()
3048
+ self.STATUS["can_skip_message"] = False
3049
+ self.DetectCartridge()
3050
+ return
2973
3051
 
2974
3052
  temp = "{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}{:s}".format(msg, msg_header_s, msg_flash_size_s, msg_save_type_s, msg_flash_mapper_s, msg_flash_id_s, msg_cfi_s, msg_cart_type_s_detail, msg_gbmem, msg_fw)
2975
3053
  temp = temp[:-4]
@@ -2999,7 +3077,27 @@ class FlashGBX_GUI(QtWidgets.QWidget):
2999
3077
  self.btnHeaderRefresh.setFocus()
3000
3078
  self.SetProgressBars(min=0, max=100, value=0)
3001
3079
  self.lblStatus4a.setText("Ready.")
3002
- return cart_type
3080
+
3081
+ waiting = None
3082
+ if "detected_cart_type" in self.STATUS and self.STATUS["detected_cart_type"] in ("WAITING_FLASH", "WAITING_SAVE_READ", "WAITING_SAVE_WRITE"):
3083
+ waiting = self.STATUS["detected_cart_type"]
3084
+ self.STATUS["detected_cart_type"] = cart_type
3085
+ self.STATUS["can_skip_message"] = False
3086
+
3087
+ if waiting == "WAITING_FLASH":
3088
+ if "detect_cartridge_args" in self.STATUS:
3089
+ self.FlashROM(dpath=self.STATUS["detect_cartridge_args"]["dpath"])
3090
+ del(self.STATUS["detect_cartridge_args"])
3091
+ else:
3092
+ self.FlashROM()
3093
+ elif waiting == "WAITING_SAVE_READ":
3094
+ self.BackupRAM()
3095
+ elif waiting == "WAITING_SAVE_WRITE":
3096
+ if "detect_cartridge_args" in self.STATUS:
3097
+ self.WriteRAM(dpath=self.STATUS["detect_cartridge_args"]["dpath"], erase=self.STATUS["detect_cartridge_args"]["erase"], skip_warning=True)
3098
+ del(self.STATUS["detect_cartridge_args"])
3099
+ else:
3100
+ self.WriteRAM()
3003
3101
 
3004
3102
  def WaitProgress(self, args):
3005
3103
  if args["user_action"] == "REINSERT_CART":
@@ -3030,6 +3128,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
3030
3128
  self.grpStatus.setTitle("Transfer Status (Write Save Data)")
3031
3129
  elif args["method"] == "SAVE_WRITE_VERIFY":
3032
3130
  self.grpStatus.setTitle("Transfer Status (Verify Save Data)")
3131
+ elif args["method"] == "DETECT_CART":
3132
+ self.grpStatus.setTitle("Transfer Status (Analyze Cartridge)")
3033
3133
 
3034
3134
  if "error" in args:
3035
3135
  self.lblStatus4a.setText("Failed!")
@@ -3113,6 +3213,11 @@ class FlashGBX_GUI(QtWidgets.QWidget):
3113
3213
  self.lblStatus4aResult.setText("")
3114
3214
  self.btnCancel.setEnabled(args["abortable"])
3115
3215
  self.SetProgressBars(min=0, max=size, value=pos)
3216
+ elif args["action"] == "UPDATE_INFO":
3217
+ self.lblStatus4a.setText(args["text"])
3218
+ self.lblStatus4aResult.setText("")
3219
+ self.btnCancel.setEnabled(args["abortable"])
3220
+ self.SetProgressBars(min=0, max=size, value=pos)
3116
3221
  elif args["action"] == "FINISHED":
3117
3222
  if pos > 0:
3118
3223
  self.lblStatus1aResult.setText(Util.formatFileSize(size=pos))
@@ -3331,18 +3436,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
3331
3436
  except:
3332
3437
  pass
3333
3438
  qt_app.exec()
3334
- # # Taskbar Progress on Windows only
3335
- # try:
3336
- # from PySide6.QtWin import QtWinTaskbarButton, QtWin
3337
- # myappid = 'lesserkuma.flashgbx'
3338
- # QtWin.setAppUserModelId(myappid)
3339
- # taskbar_button = QtWinTaskbarButton()
3340
- # self.TBPROG = taskbar_button.progress()
3341
- # self.TBPROG.setRange(0, 100)
3342
- # taskbar_button.setWindow(self.windowHandle())
3343
- # self.TBPROG.setVisible(False)
3344
- # except ImportError:
3345
- # pass
3346
3439
 
3347
3440
  else: # PySide2
3348
3441
  qt_app.exec_()