Light code refactoring
This commit is contained in:
parent
651448b6dd
commit
8e1bd5d38b
2 changed files with 231 additions and 168 deletions
387
GeckoLoader.py
387
GeckoLoader.py
|
@ -1,4 +1,4 @@
|
||||||
#Written by JoshuaMK 2020
|
# Written by JoshuaMK 2020
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import logging
|
import logging
|
||||||
|
@ -49,6 +49,7 @@ __version__ = "v7.1.0"
|
||||||
|
|
||||||
TMPDIR = Path(tempfile.mkdtemp(prefix="GeckoLoader-"))
|
TMPDIR = Path(tempfile.mkdtemp(prefix="GeckoLoader-"))
|
||||||
|
|
||||||
|
|
||||||
@atexit.register
|
@atexit.register
|
||||||
def clean_tmp_resources():
|
def clean_tmp_resources():
|
||||||
tmpfolder = TMPDIR.parent
|
tmpfolder = TMPDIR.parent
|
||||||
|
@ -56,81 +57,84 @@ def clean_tmp_resources():
|
||||||
if entry.name.startswith("GeckoLoader-"):
|
if entry.name.startswith("GeckoLoader-"):
|
||||||
shutil.rmtree(entry, ignore_errors=True)
|
shutil.rmtree(entry, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
class GeckoLoaderCli(CommandLineParser):
|
class GeckoLoaderCli(CommandLineParser):
|
||||||
|
|
||||||
def __init__(self, name, version=None, description=''):
|
def __init__(self, name, version=None, description=''):
|
||||||
super().__init__(prog=(f"{name} {version}"), description=description, allow_abbrev=False)
|
super().__init__(prog=(f"{name} {version}"),
|
||||||
|
description=description, allow_abbrev=False)
|
||||||
self.__version__ = version
|
self.__version__ = version
|
||||||
self.__doc__ = description
|
self.__doc__ = description
|
||||||
|
|
||||||
self.add_argument('dolfile', help='DOL file')
|
self.add_argument('dolfile', help='DOL file')
|
||||||
self.add_argument('codelist', help='Folder or Gecko GCT|TXT file')
|
self.add_argument('codelist', help='Folder or Gecko GCT|TXT file')
|
||||||
self.add_argument('-a', '--alloc',
|
self.add_argument('-a', '--alloc',
|
||||||
help='Define the size of the code allocation in hex, only applies when using the ARENA space',
|
help='Define the size of the code allocation in hex, only applies when using the ARENA space',
|
||||||
metavar ='SIZE')
|
metavar='SIZE')
|
||||||
self.add_argument('-i', '--init',
|
self.add_argument('-i', '--init',
|
||||||
help='Define where GeckoLoader is initialized in hex',
|
help='Define where GeckoLoader is initialized in hex',
|
||||||
metavar='ADDRESS')
|
metavar='ADDRESS')
|
||||||
self.add_argument('-tc', '--txtcodes',
|
self.add_argument('-tc', '--txtcodes',
|
||||||
help='''["ACTIVE", "ALL"] What codes get parsed when a txt file is used.
|
help='''["ACTIVE", "ALL"] What codes get parsed when a txt file is used.
|
||||||
"ALL" makes all codes get parsed,
|
"ALL" makes all codes get parsed,
|
||||||
"ACTIVE" makes only activated codes get parsed.
|
"ACTIVE" makes only activated codes get parsed.
|
||||||
"ACTIVE" is the default''',
|
"ACTIVE" is the default''',
|
||||||
default='ACTIVE',
|
default='ACTIVE',
|
||||||
metavar='TYPE')
|
metavar='TYPE')
|
||||||
self.add_argument('--handler',
|
self.add_argument('--handler',
|
||||||
help='''["MINI", "FULL"] Which codehandler gets used. "MINI" uses a smaller codehandler
|
help='''["MINI", "FULL"] Which codehandler gets used. "MINI" uses a smaller codehandler
|
||||||
which only supports (0x, 2x, Cx, and E0 types) and supports up to
|
which only supports (0x, 2x, Cx, and E0 types) and supports up to
|
||||||
600 lines of gecko codes when using the legacy codespace.
|
600 lines of gecko codes when using the legacy codespace.
|
||||||
"FULL" is the standard codehandler, supporting up to 350 lines of code
|
"FULL" is the standard codehandler, supporting up to 350 lines of code
|
||||||
in the legacy codespace. "FULL" is the default''',
|
in the legacy codespace. "FULL" is the default''',
|
||||||
default='FULL',
|
default='FULL',
|
||||||
choices=['MINI', 'FULL'],
|
choices=['MINI', 'FULL'],
|
||||||
metavar='TYPE')
|
metavar='TYPE')
|
||||||
self.add_argument('--hooktype',
|
self.add_argument('--hooktype',
|
||||||
help='''["VI", "GX", "PAD"] The type of hook used for the RAM search. "VI" or "GX" are recommended,
|
help='''["VI", "GX", "PAD"] The type of hook used for the RAM search. "VI" or "GX" are recommended,
|
||||||
although "PAD" can work just as well. "VI" is the default''',
|
although "PAD" can work just as well. "VI" is the default''',
|
||||||
default='VI',
|
default='VI',
|
||||||
choices=['VI', 'GX', 'PAD'],
|
choices=['VI', 'GX', 'PAD'],
|
||||||
metavar='HOOK')
|
metavar='HOOK')
|
||||||
self.add_argument('--hookaddress',
|
self.add_argument('--hookaddress',
|
||||||
help='Choose where the codehandler hooks to in hex, overrides auto hooks',
|
help='Choose where the codehandler hooks to in hex, overrides auto hooks',
|
||||||
metavar='ADDRESS')
|
metavar='ADDRESS')
|
||||||
self.add_argument('-o', '--optimize',
|
self.add_argument('-o', '--optimize',
|
||||||
help='''Optimizes the codelist by directly patching qualifying
|
help='''Optimizes the codelist by directly patching qualifying
|
||||||
ram writes into the dol file, and removing them from the codelist''',
|
ram writes into the dol file, and removing them from the codelist''',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('-p', '--protect',
|
self.add_argument('-p', '--protect',
|
||||||
help='''Targets and nullifies the standard codehandler provided by loaders and Dolphin Emulator,
|
help='''Targets and nullifies the standard codehandler provided by loaders and Dolphin Emulator,
|
||||||
only applies when the ARENA is used''',
|
only applies when the ARENA is used''',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('--dest',
|
self.add_argument('--dest',
|
||||||
help='Target path to put the modified DOL, can be a folder or file',
|
help='Target path to put the modified DOL, can be a folder or file',
|
||||||
metavar='PATH')
|
metavar='PATH')
|
||||||
self.add_argument('--checkupdate',
|
self.add_argument('--checkupdate',
|
||||||
help='''Checks to see if a new update exists on the GitHub Repository releases page,
|
help='''Checks to see if a new update exists on the GitHub Repository releases page,
|
||||||
this option overrides all other commands.''',
|
this option overrides all other commands.''',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('--splash',
|
self.add_argument('--splash',
|
||||||
help='''Print the splash screen, this option overrides
|
help='''Print the splash screen, this option overrides
|
||||||
all other commands excluding --checkupdate''',
|
all other commands excluding --checkupdate''',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('--encrypt',
|
self.add_argument('--encrypt',
|
||||||
help='Encrypts the codelist on compile time, helping to slow the snoopers',
|
help='Encrypts the codelist on compile time, helping to slow the snoopers',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('-q', '--quiet',
|
self.add_argument('-q', '--quiet',
|
||||||
help='Print nothing to the console',
|
help='Print nothing to the console',
|
||||||
action='store_true')
|
action='store_true')
|
||||||
self.add_argument('-v', '--verbose',
|
self.add_argument('-v', '--verbose',
|
||||||
help='Print extra info to the console',
|
help='Print extra info to the console',
|
||||||
default=0,
|
default=0,
|
||||||
action='count')
|
action='count')
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.__doc__
|
return self.__doc__
|
||||||
|
|
||||||
def print_splash(self):
|
def print_splash(self):
|
||||||
helpMessage = 'Try option -h for more info on this program'.center(64, ' ')
|
helpMessage = 'Try option -h for more info on this program'.center(
|
||||||
|
64, ' ')
|
||||||
version = self.__version__.rjust(9, ' ')
|
version = self.__version__.rjust(9, ' ')
|
||||||
|
|
||||||
logo = [' ',
|
logo = [' ',
|
||||||
|
@ -149,17 +153,18 @@ class GeckoLoaderCli(CommandLineParser):
|
||||||
' ║ ┌──┐┌┐││││ ││└──┐││┌─┐│││ │││└─┘││││││││┌┐│ ┌──┐ ║ ',
|
' ║ ┌──┐┌┐││││ ││└──┐││┌─┐│││ │││└─┘││││││││┌┐│ ┌──┐ ║ ',
|
||||||
' ║ └──┘│└┘││└─┘││└─┘│││ │││└─┘││┌─┐││││││││││└┐└──┘ ║ ',
|
' ║ └──┘│└┘││└─┘││└─┘│││ │││└─┘││┌─┐││││││││││└┐└──┘ ║ ',
|
||||||
' ║ └──┘└───┘└───┘└┘ └┘└───┘└┘ └┘└┘└┘└┘└┘└─┘ ║ ',
|
' ║ └──┘└───┘└───┘└┘ └┘└───┘└┘ └┘└┘└┘└┘└┘└─┘ ║ ',
|
||||||
f' ║ {version} ║ ',
|
f' ║ {version} ║ ',
|
||||||
' ╚═══════════════════════════════════════════════════════════╝ ',
|
' ╚═══════════════════════════════════════════════════════════╝ ',
|
||||||
' ',
|
' ',
|
||||||
' GeckoLoader is a cli tool for allowing extended ',
|
' GeckoLoader is a cli tool for allowing extended ',
|
||||||
' gecko code space in all Wii and GC games. ',
|
' gecko code space in all Wii and GC games. ',
|
||||||
' ',
|
' ',
|
||||||
f'{helpMessage}',
|
f'{helpMessage}',
|
||||||
' ']
|
' ']
|
||||||
|
|
||||||
for line in logo:
|
for line in logo:
|
||||||
print(color_text(line, [('║', TREDLIT), ('╔╚╝╗═', TRED)], TGREENLIT))
|
print(color_text(
|
||||||
|
line, [('║', TREDLIT), ('╔╚╝╗═', TRED)], TGREENLIT))
|
||||||
|
|
||||||
def check_updates(self):
|
def check_updates(self):
|
||||||
repoChecker = Updater('JoshuaMKW', 'GeckoLoader')
|
repoChecker = Updater('JoshuaMKW', 'GeckoLoader')
|
||||||
|
@ -167,39 +172,57 @@ class GeckoLoaderCli(CommandLineParser):
|
||||||
tag, status = repoChecker.get_newest_version()
|
tag, status = repoChecker.get_newest_version()
|
||||||
|
|
||||||
if status is False:
|
if status is False:
|
||||||
self.error(color_text(tag + '\n', defaultColor=TREDLIT), print_usage=False)
|
self.error(color_text(tag + '\n', defaultColor=TREDLIT),
|
||||||
|
print_usage=False)
|
||||||
|
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
if LooseVersion(tag) > LooseVersion(self.__version__):
|
if LooseVersion(tag) > LooseVersion(self.__version__):
|
||||||
print(color_text(f' :: A new update is live at {repoChecker.gitReleases.format(repoChecker.owner, repoChecker.repo)}', defaultColor=TYELLOWLIT))
|
print(color_text(
|
||||||
print(color_text(f' :: Current version is "{self.__version__}", Most recent version is "{tag}"', defaultColor=TYELLOWLIT))
|
f' :: A new update is live at {repoChecker.gitReleases.format(repoChecker.owner, repoChecker.repo)}', defaultColor=TYELLOWLIT))
|
||||||
|
print(color_text(
|
||||||
|
f' :: Current version is "{self.__version__}", Most recent version is "{tag}"', defaultColor=TYELLOWLIT))
|
||||||
elif LooseVersion(tag) < LooseVersion(self.__version__):
|
elif LooseVersion(tag) < LooseVersion(self.__version__):
|
||||||
print(color_text(' :: No update available', defaultColor=TGREENLIT))
|
print(color_text(' :: No update available', defaultColor=TGREENLIT))
|
||||||
print(color_text(f' :: Current version is "{self.__version__}(dev)", Most recent version is "{tag}(release)"', defaultColor=TGREENLIT))
|
print(color_text(
|
||||||
|
f' :: Current version is "{self.__version__}(dev)", Most recent version is "{tag}(release)"', defaultColor=TGREENLIT))
|
||||||
else:
|
else:
|
||||||
print(color_text(' :: No update available', defaultColor=TGREENLIT))
|
print(color_text(' :: No update available', defaultColor=TGREENLIT))
|
||||||
print(color_text(f' :: Current version is "{self.__version__}(release)", Most recent version is "{tag}(release)"', defaultColor=TGREENLIT))
|
print(color_text(
|
||||||
|
f' :: Current version is "{self.__version__}(release)", Most recent version is "{tag}(release)"', defaultColor=TGREENLIT))
|
||||||
|
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
def _validate_args(self, args) -> tuple:
|
def _validate_args(self, args) -> dict:
|
||||||
|
dolFile = Path(args.dolfile).resolve()
|
||||||
|
codeList = Path(args.codelist).resolve()
|
||||||
|
|
||||||
|
if args.dest:
|
||||||
|
dest = Path(args.dest).resolve()
|
||||||
|
if dest.suffix == "":
|
||||||
|
dest = dest / args.dolfile.name
|
||||||
|
else:
|
||||||
|
dest = Path.cwd() / "geckoloader-build" / args.dolfile.name
|
||||||
|
|
||||||
if args.alloc:
|
if args.alloc:
|
||||||
try:
|
try:
|
||||||
_allocation = int(args.alloc, 16)
|
_allocation = int(args.alloc, 16)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.error(color_text('The allocation was invalid\n', defaultColor=TREDLIT))
|
self.error(color_text(
|
||||||
|
'The allocation was invalid\n', defaultColor=TREDLIT))
|
||||||
else:
|
else:
|
||||||
_allocation = None
|
_allocation = None
|
||||||
|
|
||||||
if args.hookaddress:
|
if args.hookaddress:
|
||||||
if 0x80000000 > int(args.hookaddress, 16) >= 0x81800000:
|
if 0x80000000 > int(args.hookaddress, 16) >= 0x81800000:
|
||||||
self.error(color_text('The codehandler hook address was beyond bounds\n', defaultColor=TREDLIT))
|
self.error(color_text(
|
||||||
|
'The codehandler hook address was beyond bounds\n', defaultColor=TREDLIT))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
_codehook = int(args.hookaddress, 16)
|
_codehook = int(args.hookaddress, 16)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.error(color_text('The codehandler hook address was invalid\n', defaultColor=TREDLIT))
|
self.error(color_text(
|
||||||
|
'The codehandler hook address was invalid\n', defaultColor=TREDLIT))
|
||||||
else:
|
else:
|
||||||
_codehook = None
|
_codehook = None
|
||||||
|
|
||||||
|
@ -208,57 +231,65 @@ class GeckoLoaderCli(CommandLineParser):
|
||||||
elif args.handler == CodeHandler.Types.FULL:
|
elif args.handler == CodeHandler.Types.FULL:
|
||||||
codeHandlerFile = Path('bin/codehandler.bin')
|
codeHandlerFile = Path('bin/codehandler.bin')
|
||||||
else:
|
else:
|
||||||
self.error(color_text(f'Codehandler type {args.handler} is invalid\n', defaultColor=TREDLIT))
|
self.error(color_text(
|
||||||
|
f'Codehandler type {args.handler} is invalid\n', defaultColor=TREDLIT))
|
||||||
|
|
||||||
if not os.path.isfile(args.dolfile):
|
if not dolFile.is_file():
|
||||||
self.error(color_text(f'File "{args.dolfile}" does not exist\n', defaultColor=TREDLIT))
|
self.error(color_text(
|
||||||
|
f'File "{dolFile}" does not exist\n', defaultColor=TREDLIT))
|
||||||
if not os.path.exists(args.codelist):
|
|
||||||
self.error(color_text(f'File/folder "{args.codelist}" does not exist\n', defaultColor=TREDLIT))
|
|
||||||
|
|
||||||
return _allocation, _codehook, codeHandlerFile
|
if not codeList.exists():
|
||||||
|
self.error(color_text(
|
||||||
|
f'File/folder "{codeList}" does not exist\n', defaultColor=TREDLIT))
|
||||||
|
|
||||||
|
return {"dol": dolFile,
|
||||||
|
"codepath": codeList,
|
||||||
|
"codehandler": codeHandlerFile,
|
||||||
|
"destination": dest,
|
||||||
|
"allocation": _allocation,
|
||||||
|
"hookaddress": _codehook,
|
||||||
|
"hooktype": args.hooktype,
|
||||||
|
"initaddress": None if args.init is None else int(args.init, 16),
|
||||||
|
"includeall": args.txtcodes.lower() == "all",
|
||||||
|
"optimize": args.optimize,
|
||||||
|
"protect": args.protect,
|
||||||
|
"encrypt": args.encrypt,
|
||||||
|
"verbosity": args.verbose,
|
||||||
|
"quiet": args.quiet}
|
||||||
|
|
||||||
def _exec(self, args, tmpdir):
|
def _exec(self, args, tmpdir):
|
||||||
_allocation, _codehook, codeHandlerFile = self._validate_args(args)
|
context = self._validate_args(args)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(args.dolfile, "rb") as dol:
|
with context["dol"].open("rb") as dol:
|
||||||
dolFile = DolFile(dol)
|
dolFile = DolFile(dol)
|
||||||
|
|
||||||
with resource_path(str(codeHandlerFile)).open("rb") as handler:
|
with resource_path(context["codehandler"]).open("rb") as handler:
|
||||||
codeHandler = CodeHandler(handler)
|
codeHandler = CodeHandler(handler)
|
||||||
codeHandler.allocation = _allocation
|
codeHandler.allocation = context["allocation"]
|
||||||
codeHandler.hookAddress = _codehook
|
codeHandler.hookAddress = context["hookaddress"]
|
||||||
codeHandler.hookType = args.hooktype
|
codeHandler.hookType = context["hooktype"]
|
||||||
codeHandler.includeAll = args.txtcodes.lower() == 'all'
|
codeHandler.includeAll = context["includeall"]
|
||||||
codeHandler.optimizeList = args.optimize
|
codeHandler.optimizeList = context["optimize"]
|
||||||
|
|
||||||
with resource_path("bin/geckoloader.bin").open("rb") as kernelfile:
|
with resource_path("bin/geckoloader.bin").open("rb") as kernelfile:
|
||||||
geckoKernel = KernelLoader(kernelfile, cli)
|
geckoKernel = KernelLoader(kernelfile, cli)
|
||||||
|
geckoKernel.initAddress = context["initaddress"]
|
||||||
|
geckoKernel.verbosity = context["verbosity"]
|
||||||
|
geckoKernel.quiet = context["quiet"]
|
||||||
|
geckoKernel.encrypt = context["encrypt"]
|
||||||
|
geckoKernel.protect = context["protect"]
|
||||||
|
|
||||||
if args.init is not None:
|
if not context["destination"].parent.exists():
|
||||||
geckoKernel.initAddress = int(args.init, 16)
|
context["destination"].parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
geckoKernel.verbosity = args.verbose
|
geckoKernel.build(context["codepath"], dolFile,
|
||||||
geckoKernel.quiet = args.quiet
|
codeHandler, TMPDIR, context["destination"])
|
||||||
geckoKernel.encrypt = args.encrypt
|
|
||||||
geckoKernel.protect = args.protect
|
|
||||||
|
|
||||||
if args.dest:
|
|
||||||
dest = Path(args.dest).resolve()
|
|
||||||
if dest.suffix == "":
|
|
||||||
dest = dest / args.dolfile.name
|
|
||||||
else:
|
|
||||||
dest = Path.cwd() / "geckoloader-build" / args.dolfile.name
|
|
||||||
|
|
||||||
if not dest.parent.exists():
|
|
||||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
geckoKernel.build(Path(args.codelist), dolFile, codeHandler, TMPDIR, dest)
|
|
||||||
|
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
self.error(color_text(e, defaultColor=TREDLIT))
|
self.error(color_text(e, defaultColor=TREDLIT))
|
||||||
|
|
||||||
|
|
||||||
class GUI(object):
|
class GUI(object):
|
||||||
|
|
||||||
class Dialogs:
|
class Dialogs:
|
||||||
|
@ -289,8 +320,10 @@ class GUI(object):
|
||||||
if not get_program_folder("GeckoLoader").exists():
|
if not get_program_folder("GeckoLoader").exists():
|
||||||
get_program_folder("GeckoLoader").mkdir()
|
get_program_folder("GeckoLoader").mkdir()
|
||||||
|
|
||||||
hdlr = logging.FileHandler(get_program_folder("GeckoLoader") / "error.log")
|
hdlr = logging.FileHandler(
|
||||||
formatter = logging.Formatter("\n%(levelname)s (%(asctime)s): %(message)s")
|
get_program_folder("GeckoLoader") / "error.log")
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
"\n%(levelname)s (%(asctime)s): %(message)s")
|
||||||
hdlr.setFormatter(formatter)
|
hdlr.setFormatter(formatter)
|
||||||
self.log.addHandler(hdlr)
|
self.log.addHandler(hdlr)
|
||||||
|
|
||||||
|
@ -298,18 +331,19 @@ class GUI(object):
|
||||||
if dialog_type == "aboutqt":
|
if dialog_type == "aboutqt":
|
||||||
QtWidgets.QMessageBox.aboutQt(self.app.activeWindow())
|
QtWidgets.QMessageBox.aboutQt(self.app.activeWindow())
|
||||||
elif dialog_type == "aboutGeckoLoader":
|
elif dialog_type == "aboutGeckoLoader":
|
||||||
desc = "".join([ "GeckoLoader is a cross platform tool designed to give ",
|
desc = "".join(["GeckoLoader is a cross platform tool designed to give ",
|
||||||
"the user the most efficient codespace usage possible.\n\n ",
|
"the user the most efficient codespace usage possible.\n\n ",
|
||||||
"This application supports various features, such as ",
|
"This application supports various features, such as ",
|
||||||
"pre-patching codes, dynamic codehandler hooks, codespace ",
|
"pre-patching codes, dynamic codehandler hooks, codespace ",
|
||||||
"extension through memory reallocation, multiple patching ",
|
"extension through memory reallocation, multiple patching ",
|
||||||
"of a single DOL, and more.\n\n",
|
"of a single DOL, and more.\n\n",
|
||||||
f"Current running version: {self.version}\n\n"
|
f"Current running version: {self.version}\n\n"
|
||||||
"Copyright (c) 2020\n\n",
|
"Copyright (c) 2020\n\n",
|
||||||
"JoshuaMK <joshuamkw2002@gmail.com> \n\n",
|
"JoshuaMK <joshuamkw2002@gmail.com> \n\n",
|
||||||
"All rights reserved." ])
|
"All rights reserved."])
|
||||||
|
|
||||||
QtWidgets.QMessageBox.about(self.app.activeWindow(), "About GeckoLoader", desc)
|
QtWidgets.QMessageBox.about(
|
||||||
|
self.app.activeWindow(), "About GeckoLoader", desc)
|
||||||
elif dialog_type == "Preferences":
|
elif dialog_type == "Preferences":
|
||||||
self.uiprefs.show()
|
self.uiprefs.show()
|
||||||
else:
|
else:
|
||||||
|
@ -322,10 +356,10 @@ class GUI(object):
|
||||||
def _open_dol(self) -> tuple:
|
def _open_dol(self) -> tuple:
|
||||||
if self.dolPath is None: # Just start in the home directory
|
if self.dolPath is None: # Just start in the home directory
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(Path.home()),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(Path.home()),
|
||||||
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
||||||
else: # Start in the last directory used by the user
|
else: # Start in the last directory used by the user
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(self.dolPath.parent),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(self.dolPath.parent),
|
||||||
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
||||||
|
|
||||||
if fname == "" or fname is None: # Make sure we have something to open
|
if fname == "" or fname is None: # Make sure we have something to open
|
||||||
return False, None
|
return False, None
|
||||||
|
@ -338,21 +372,21 @@ class GUI(object):
|
||||||
else:
|
else:
|
||||||
return False, "The file does not exist!"
|
return False, "The file does not exist!"
|
||||||
|
|
||||||
def _load_codes(self, isFolder: bool=False) -> tuple:
|
def _load_codes(self, isFolder: bool = False) -> tuple:
|
||||||
if not isFolder:
|
if not isFolder:
|
||||||
if self.codePath[0] is None: # Just start in the home directory
|
if self.codePath[0] is None: # Just start in the home directory
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Codelist", str(Path.home()),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Codelist", str(Path.home()),
|
||||||
"Gecko Code Table (*.gct);;Gecko Codelist (*.txt);;All files (*)")[0])
|
"Gecko Code Table (*.gct);;Gecko Codelist (*.txt);;All files (*)")[0])
|
||||||
else: # Start in the last directory used by the user
|
else: # Start in the last directory used by the user
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Codelist", str(self.codePath[0].parent),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Codelist", str(self.codePath[0].parent),
|
||||||
"Gecko Code Table (*.gct);;Gecko Codelist (*.txt);;All files (*)")[0])
|
"Gecko Code Table (*.gct);;Gecko Codelist (*.txt);;All files (*)")[0])
|
||||||
else:
|
else:
|
||||||
if self.codePath[0] is None: # Just start in the home directory
|
if self.codePath[0] is None: # Just start in the home directory
|
||||||
fname = str(QtWidgets.QFileDialog.getExistingDirectory(self.ui, "Open Codelist", str(Path.home()),
|
fname = str(QtWidgets.QFileDialog.getExistingDirectory(self.ui, "Open Codelist", str(Path.home()),
|
||||||
QtWidgets.QFileDialog.ShowDirsOnly))
|
QtWidgets.QFileDialog.ShowDirsOnly))
|
||||||
else: # Start in the last directory used by the user
|
else: # Start in the last directory used by the user
|
||||||
fname = str(QtWidgets.QFileDialog.getExistingDirectory(self.ui, "Open Codelist", str(self.codePath[0].parent),
|
fname = str(QtWidgets.QFileDialog.getExistingDirectory(self.ui, "Open Codelist", str(self.codePath[0].parent),
|
||||||
QtWidgets.QFileDialog.ShowDirsOnly))
|
QtWidgets.QFileDialog.ShowDirsOnly))
|
||||||
|
|
||||||
if fname == "" or fname is None: # Make sure we have something to open
|
if fname == "" or fname is None: # Make sure we have something to open
|
||||||
return False, None
|
return False, None
|
||||||
|
@ -371,10 +405,10 @@ class GUI(object):
|
||||||
def _open_dest(self) -> tuple:
|
def _open_dest(self) -> tuple:
|
||||||
if self.dolPath is None: # Just start in the home directory
|
if self.dolPath is None: # Just start in the home directory
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(Path.home()),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(Path.home()),
|
||||||
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
||||||
else: # Start in the last directory used by the user
|
else: # Start in the last directory used by the user
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(self.dolPath.parent),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open DOL", str(self.dolPath.parent),
|
||||||
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
"Nintendo DOL Executable (*.dol);;All files (*)")[0])
|
||||||
|
|
||||||
if fname == "" or fname is None: # Make sure we have something to open
|
if fname == "" or fname is None: # Make sure we have something to open
|
||||||
return False, None
|
return False, None
|
||||||
|
@ -387,10 +421,10 @@ class GUI(object):
|
||||||
def _load_session(self) -> tuple:
|
def _load_session(self) -> tuple:
|
||||||
if self.sessionPath is None:
|
if self.sessionPath is None:
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Session", str(Path.home()),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Session", str(Path.home()),
|
||||||
"GeckoLoader Session (*.gprf);;All files (*)")[0])
|
"GeckoLoader Session (*.gprf);;All files (*)")[0])
|
||||||
else: # Start in the last directory used by the user
|
else: # Start in the last directory used by the user
|
||||||
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Session", str(self.sessionPath.parent),
|
fname = str(QtWidgets.QFileDialog.getOpenFileName(self.ui, "Open Session", str(self.sessionPath.parent),
|
||||||
"GeckoLoader Session (*.gprf);;All files (*)")[0])
|
"GeckoLoader Session (*.gprf);;All files (*)")[0])
|
||||||
|
|
||||||
if fname == "" or fname is None: # Make sure we have something to open
|
if fname == "" or fname is None: # Make sure we have something to open
|
||||||
return False, None
|
return False, None
|
||||||
|
@ -422,7 +456,8 @@ class GUI(object):
|
||||||
self.uiexSettings.encryptCodes.setChecked(p["encrypt"])
|
self.uiexSettings.encryptCodes.setChecked(p["encrypt"])
|
||||||
self.uiexSettings.codehookLineEdit.setText(p["hookAddress"])
|
self.uiexSettings.codehookLineEdit.setText(p["hookAddress"])
|
||||||
self.uiexSettings.kernelHookLineEdit.setText(p["initAddress"])
|
self.uiexSettings.kernelHookLineEdit.setText(p["initAddress"])
|
||||||
self.uiexSettings.verbositySelect.setCurrentIndex(p["verbosity"])
|
self.uiexSettings.verbositySelect.setCurrentIndex(
|
||||||
|
p["verbosity"])
|
||||||
|
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
|
@ -463,7 +498,7 @@ class GUI(object):
|
||||||
cPickle.dump(p, session)
|
cPickle.dump(p, session)
|
||||||
except cPickle.PicklingError as e:
|
except cPickle.PicklingError as e:
|
||||||
return False, str(e)
|
return False, str(e)
|
||||||
|
|
||||||
return True, None
|
return True, None
|
||||||
except (IOError, PermissionError) as e:
|
except (IOError, PermissionError) as e:
|
||||||
return False, str(e)
|
return False, str(e)
|
||||||
|
@ -489,7 +524,7 @@ class GUI(object):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
self.ui.set_edit_fields()
|
self.ui.set_edit_fields()
|
||||||
return
|
return
|
||||||
|
|
||||||
if status is False and msg is not None:
|
if status is False and msg is not None:
|
||||||
reply = QtWidgets.QErrorMessage(self)
|
reply = QtWidgets.QErrorMessage(self)
|
||||||
reply.setWindowTitle("I/O Failure")
|
reply.setWindowTitle("I/O Failure")
|
||||||
|
@ -534,7 +569,7 @@ class GUI(object):
|
||||||
else:
|
else:
|
||||||
# Input validation
|
# Input validation
|
||||||
if (p.get("qtstyle") in list(QtWidgets.QStyleFactory.keys()) or
|
if (p.get("qtstyle") in list(QtWidgets.QStyleFactory.keys()) or
|
||||||
p.get("qtstyle") == "Default"):
|
p.get("qtstyle") == "Default"):
|
||||||
self.prefs["qtstyle"] = p.get("qtstyle")
|
self.prefs["qtstyle"] = p.get("qtstyle")
|
||||||
|
|
||||||
if p.get("darktheme") in (True, False):
|
if p.get("darktheme") in (True, False):
|
||||||
|
@ -549,15 +584,16 @@ class GUI(object):
|
||||||
self.prefs.get("qtstyle"),
|
self.prefs.get("qtstyle"),
|
||||||
flags=QtCore.Qt.MatchFixedString))
|
flags=QtCore.Qt.MatchFixedString))
|
||||||
|
|
||||||
self.uiprefs.qtdarkButton.setChecked(self.prefs.get("darktheme"))
|
self.uiprefs.qtdarkButton.setChecked(
|
||||||
|
self.prefs.get("darktheme"))
|
||||||
self.update_theme()
|
self.update_theme()
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.log.warning("No preferences file found; using defaults.")
|
self.log.warning("No preferences file found; using defaults.")
|
||||||
|
|
||||||
def save_prefs(self):
|
def save_prefs(self):
|
||||||
datapath = get_program_folder("GeckoLoader")
|
datapath = get_program_folder("GeckoLoader")
|
||||||
|
|
||||||
self.prefs["qtstyle"] = str(self.uiprefs.qtstyleSelect.currentText())
|
self.prefs["qtstyle"] = str(self.uiprefs.qtstyleSelect.currentText())
|
||||||
self.prefs["darktheme"] = self.uiprefs.qtdarkButton.isChecked()
|
self.prefs["darktheme"] = self.uiprefs.qtdarkButton.isChecked()
|
||||||
|
|
||||||
|
@ -568,7 +604,8 @@ class GUI(object):
|
||||||
self.log.exception(e)
|
self.log.exception(e)
|
||||||
|
|
||||||
def load_qtstyle(self, style, first_style_load=False):
|
def load_qtstyle(self, style, first_style_load=False):
|
||||||
self.style_log.append([self.app.style, self.uiprefs.qtstyleSelect.currentText()])
|
self.style_log.append(
|
||||||
|
[self.app.style, self.uiprefs.qtstyleSelect.currentText()])
|
||||||
|
|
||||||
if len(self.style_log) > 2:
|
if len(self.style_log) > 2:
|
||||||
self.style_log.pop(0)
|
self.style_log.pop(0)
|
||||||
|
@ -606,14 +643,16 @@ class GUI(object):
|
||||||
_status = True
|
_status = True
|
||||||
|
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(QtGui.QPixmap(str(resource_path(Path("bin/icon.ico")))), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon.addPixmap(QtGui.QPixmap(
|
||||||
|
str(resource_path(Path("bin/icon.ico")))), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
|
||||||
if _status is False:
|
if _status is False:
|
||||||
reply = QtWidgets.QErrorMessage()
|
reply = QtWidgets.QErrorMessage()
|
||||||
reply.setWindowIcon(icon)
|
reply.setWindowIcon(icon)
|
||||||
reply.setWindowTitle("Response Error")
|
reply.setWindowTitle("Response Error")
|
||||||
reply.setText(self._remove_ansi(_errpipe.getvalue()))
|
reply.setText(self._remove_ansi(_errpipe.getvalue()))
|
||||||
reply.setInformativeText("Make sure you have an internet connection")
|
reply.setInformativeText(
|
||||||
|
"Make sure you have an internet connection")
|
||||||
reply.setIcon(QtWidgets.QMessageBox.Warning)
|
reply.setIcon(QtWidgets.QMessageBox.Warning)
|
||||||
reply.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
reply.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
||||||
reply.exec_()
|
reply.exec_()
|
||||||
|
@ -621,7 +660,8 @@ class GUI(object):
|
||||||
reply = QtWidgets.QMessageBox()
|
reply = QtWidgets.QMessageBox()
|
||||||
reply.setWindowIcon(icon)
|
reply.setWindowIcon(icon)
|
||||||
reply.setWindowTitle("Update Info")
|
reply.setWindowTitle("Update Info")
|
||||||
reply.setText(self._remove_ansi(_outpipe.getvalue()).strip("\n") + "\n\nYou can find all GeckoLoader releases at:\nhttps://github.com/JoshuaMKW/GeckoLoader/releases")
|
reply.setText(self._remove_ansi(_outpipe.getvalue()).strip(
|
||||||
|
"\n") + "\n\nYou can find all GeckoLoader releases at:\nhttps://github.com/JoshuaMKW/GeckoLoader/releases")
|
||||||
reply.setIcon(QtWidgets.QMessageBox.Information)
|
reply.setIcon(QtWidgets.QMessageBox.Information)
|
||||||
reply.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
reply.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
||||||
reply.exec_()
|
reply.exec_()
|
||||||
|
@ -631,9 +671,11 @@ class GUI(object):
|
||||||
textbox.setText(textbox.text().strip())
|
textbox.setText(textbox.text().strip())
|
||||||
if len(textbox.text()) > 0:
|
if len(textbox.text()) > 0:
|
||||||
_depth = len(hex(mask)[2:])
|
_depth = len(hex(mask)[2:])
|
||||||
_address = int(textbox.text(), 16) << ((_depth - len(textbox.text())) << 2)
|
_address = int(textbox.text(), 16) << (
|
||||||
|
(_depth - len(textbox.text())) << 2)
|
||||||
aligned = hex(((_address & mask) | _or) >> ((_depth - len(textbox.text())) << 2))[2:].upper()
|
|
||||||
|
aligned = hex(((_address & mask) | _or) >> (
|
||||||
|
(_depth - len(textbox.text())) << 2))[2:].upper()
|
||||||
textbox.setText(aligned)
|
textbox.setText(aligned)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -642,50 +684,73 @@ class GUI(object):
|
||||||
return ansi_escape.sub('', msg)
|
return ansi_escape.sub('', msg)
|
||||||
|
|
||||||
def connect_signals(self):
|
def connect_signals(self):
|
||||||
self.ui.actionPreferences.triggered.connect(lambda: self.show_dialog("Preferences"))
|
self.ui.actionPreferences.triggered.connect(
|
||||||
self.ui.actionAbout_Qt.triggered.connect(lambda: self.show_dialog("aboutqt"))
|
lambda: self.show_dialog("Preferences"))
|
||||||
self.ui.actionAbout_GeckoLoader.triggered.connect(lambda: self.show_dialog("aboutGeckoLoader"))
|
self.ui.actionAbout_Qt.triggered.connect(
|
||||||
self.ui.actionCheck_Update.triggered.connect(lambda: self.display_update())
|
lambda: self.show_dialog("aboutqt"))
|
||||||
|
self.ui.actionAbout_GeckoLoader.triggered.connect(
|
||||||
|
lambda: self.show_dialog("aboutGeckoLoader"))
|
||||||
|
self.ui.actionCheck_Update.triggered.connect(
|
||||||
|
lambda: self.display_update())
|
||||||
|
|
||||||
self.ui.actionOpen.triggered.connect(lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_SESSION))
|
self.ui.actionOpen.triggered.connect(
|
||||||
|
lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_SESSION))
|
||||||
self.ui.actionClose.triggered.connect(lambda: self.close_session())
|
self.ui.actionClose.triggered.connect(lambda: self.close_session())
|
||||||
self.ui.actionSave_As.triggered.connect(lambda: self.file_dialog_exec(GUI.Dialogs.SAVE_SESSION_AS))
|
self.ui.actionSave_As.triggered.connect(
|
||||||
self.ui.actionSave.triggered.connect(lambda: self.file_dialog_exec(GUI.Dialogs.SAVE_SESSION))
|
lambda: self.file_dialog_exec(GUI.Dialogs.SAVE_SESSION_AS))
|
||||||
|
self.ui.actionSave.triggered.connect(
|
||||||
|
lambda: self.file_dialog_exec(GUI.Dialogs.SAVE_SESSION))
|
||||||
|
|
||||||
self.ui.dolButton.clicked.connect(lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_DOL))
|
self.ui.dolButton.clicked.connect(
|
||||||
self.ui.gctFileButton.clicked.connect(lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_GCT))
|
lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_DOL))
|
||||||
self.ui.gctFolderButton.clicked.connect(lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_FOLDER))
|
self.ui.gctFileButton.clicked.connect(
|
||||||
self.ui.destButton.clicked.connect(lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_DEST))
|
lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_GCT))
|
||||||
|
self.ui.gctFolderButton.clicked.connect(
|
||||||
|
lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_FOLDER))
|
||||||
|
self.ui.destButton.clicked.connect(
|
||||||
|
lambda: self.file_dialog_exec(GUI.Dialogs.LOAD_DEST))
|
||||||
|
|
||||||
self.ui.dolTextBox.textChanged.connect(lambda: self.ui.set_edit_fields())
|
self.ui.dolTextBox.textChanged.connect(
|
||||||
self.ui.gctFolderTextBox.textChanged.connect(lambda: self.ui.set_edit_fields())
|
lambda: self.ui.set_edit_fields())
|
||||||
self.ui.gctFileTextBox.textChanged.connect(lambda: self.ui.set_edit_fields())
|
self.ui.gctFolderTextBox.textChanged.connect(
|
||||||
self.ui.destTextBox.textChanged.connect(lambda: self.ui.set_edit_fields())
|
lambda: self.ui.set_edit_fields())
|
||||||
|
self.ui.gctFileTextBox.textChanged.connect(
|
||||||
|
lambda: self.ui.set_edit_fields())
|
||||||
|
self.ui.destTextBox.textChanged.connect(
|
||||||
|
lambda: self.ui.set_edit_fields())
|
||||||
|
|
||||||
self.ui.allocLineEdit.textChanged.connect(lambda: self._enforce_mask(self.ui.allocLineEdit, 0xFFFFFC))
|
self.ui.allocLineEdit.textChanged.connect(
|
||||||
|
lambda: self._enforce_mask(self.ui.allocLineEdit, 0xFFFFFC))
|
||||||
|
|
||||||
self.ui.exOptionsButton.clicked.connect(lambda: self.show_dialog("Advanced Settings"))
|
self.ui.exOptionsButton.clicked.connect(
|
||||||
|
lambda: self.show_dialog("Advanced Settings"))
|
||||||
self.ui.compileButton.clicked.connect(lambda: self._exec_api())
|
self.ui.compileButton.clicked.connect(lambda: self._exec_api())
|
||||||
|
|
||||||
self.uiprefs.buttonBox.accepted.connect(self.save_prefs)
|
self.uiprefs.buttonBox.accepted.connect(self.save_prefs)
|
||||||
self.uiprefs.qtstyleSelect.currentIndexChanged.connect(lambda: self.load_qtstyle(self.uiprefs.qtstyleSelect.currentText()))
|
self.uiprefs.qtstyleSelect.currentIndexChanged.connect(
|
||||||
|
lambda: self.load_qtstyle(self.uiprefs.qtstyleSelect.currentText()))
|
||||||
self.uiprefs.qtdarkButton.clicked.connect(lambda: self.update_theme())
|
self.uiprefs.qtdarkButton.clicked.connect(lambda: self.update_theme())
|
||||||
|
|
||||||
self.uiexSettings.codehookLineEdit.textChanged.connect(lambda: self._enforce_mask(self.uiexSettings.codehookLineEdit, 0x817FFFFC, 0x80000000))
|
self.uiexSettings.codehookLineEdit.textChanged.connect(lambda: self._enforce_mask(
|
||||||
self.uiexSettings.kernelHookLineEdit.textChanged.connect(lambda: self._enforce_mask(self.uiexSettings.kernelHookLineEdit, 0x817FFFFC, 0x80000000))
|
self.uiexSettings.codehookLineEdit, 0x817FFFFC, 0x80000000))
|
||||||
|
self.uiexSettings.kernelHookLineEdit.textChanged.connect(lambda: self._enforce_mask(
|
||||||
|
self.uiexSettings.kernelHookLineEdit, 0x817FFFFC, 0x80000000))
|
||||||
|
|
||||||
def _exec_api(self):
|
def _exec_api(self):
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
self.ui.responses.appendPlainText(f"| Session {self.compileCount} |".center(84, "=") + "\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
f"| Session {self.compileCount} |".center(84, "=") + "\n")
|
||||||
else:
|
else:
|
||||||
self.ui.responses.appendPlainText(f"| Session {self.compileCount} |".center(76, "=") + "\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
f"| Session {self.compileCount} |".center(76, "=") + "\n")
|
||||||
|
|
||||||
self.compileCount += 1
|
self.compileCount += 1
|
||||||
|
|
||||||
if self.ui.dolTextBox.isEnabled and self.ui.dolTextBox.text().strip() != "":
|
if self.ui.dolTextBox.isEnabled and self.ui.dolTextBox.text().strip() != "":
|
||||||
dol = self.ui.dolTextBox.text().strip()
|
dol = self.ui.dolTextBox.text().strip()
|
||||||
else:
|
else:
|
||||||
self.ui.responses.appendPlainText("DOL is missing, please add the path to your codes in the respective textbox" + "\n\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
"DOL is missing, please add the path to your codes in the respective textbox" + "\n\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.ui.gctFileTextBox.isEnabled and self.ui.gctFileTextBox.text().strip() != "":
|
if self.ui.gctFileTextBox.isEnabled and self.ui.gctFileTextBox.text().strip() != "":
|
||||||
|
@ -693,7 +758,8 @@ class GUI(object):
|
||||||
elif self.ui.gctFolderTextBox.isEnabled and self.ui.gctFolderTextBox.text().strip() != "":
|
elif self.ui.gctFolderTextBox.isEnabled and self.ui.gctFolderTextBox.text().strip() != "":
|
||||||
gct = self.ui.gctFolderTextBox.text().strip()
|
gct = self.ui.gctFolderTextBox.text().strip()
|
||||||
else:
|
else:
|
||||||
self.ui.responses.appendPlainText("GCT is missing, please add the path to your codes in the respective textbox" + "\n\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
"GCT is missing, please add the path to your codes in the respective textbox" + "\n\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
alloc = self.ui.allocLineEdit.text().strip()
|
alloc = self.ui.allocLineEdit.text().strip()
|
||||||
|
@ -705,18 +771,21 @@ class GUI(object):
|
||||||
optimize = self.uiexSettings.optimizeCodes.isChecked()
|
optimize = self.uiexSettings.optimizeCodes.isChecked()
|
||||||
protect = self.uiexSettings.protectCodes.isChecked()
|
protect = self.uiexSettings.protectCodes.isChecked()
|
||||||
encrypt = self.uiexSettings.encryptCodes.isChecked()
|
encrypt = self.uiexSettings.encryptCodes.isChecked()
|
||||||
verbosity = int(self.uiexSettings.verbositySelect.currentText().strip())
|
verbosity = int(
|
||||||
|
self.uiexSettings.verbositySelect.currentText().strip())
|
||||||
dest = self.ui.destTextBox.text().strip()
|
dest = self.ui.destTextBox.text().strip()
|
||||||
|
|
||||||
argslist = [ dol, gct, "-t", txtInclude, "--handler", codeHandlerType, "--hooktype", hookType ]
|
argslist = [dol, gct, "-t", txtInclude, "--handler",
|
||||||
|
codeHandlerType, "--hooktype", hookType]
|
||||||
|
|
||||||
if alloc != "":
|
if alloc != "":
|
||||||
argslist.append("-a")
|
argslist.append("-a")
|
||||||
argslist.append(hex(int(alloc, 16) & 0xFFFFFC)[2:].upper())
|
argslist.append(hex(int(alloc, 16) & 0xFFFFFC)[2:].upper())
|
||||||
|
|
||||||
if hookAddress != "":
|
if hookAddress != "":
|
||||||
if int(hookAddress, 16) < 0x80000000:
|
if int(hookAddress, 16) < 0x80000000:
|
||||||
self.ui.responses.appendPlainText("The specified code hook is invalid" + "\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
"The specified code hook is invalid" + "\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
argslist.append("--hookaddress")
|
argslist.append("--hookaddress")
|
||||||
|
@ -724,7 +793,8 @@ class GUI(object):
|
||||||
|
|
||||||
if initAddress != "":
|
if initAddress != "":
|
||||||
if int(initAddress, 16) < 0x80000000:
|
if int(initAddress, 16) < 0x80000000:
|
||||||
self.ui.responses.appendPlainText("The specified initialization address is invalid" + "\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
"The specified initialization address is invalid" + "\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
argslist.append("-i")
|
argslist.append("-i")
|
||||||
|
@ -735,7 +805,8 @@ class GUI(object):
|
||||||
argslist.append("--dest")
|
argslist.append("--dest")
|
||||||
argslist.append(dest)
|
argslist.append(dest)
|
||||||
else:
|
else:
|
||||||
self.ui.responses.appendPlainText("The destination file path is not a valid DOL file\n")
|
self.ui.responses.appendPlainText(
|
||||||
|
"The destination file path is not a valid DOL file\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
if optimize:
|
if optimize:
|
||||||
|
@ -751,7 +822,7 @@ class GUI(object):
|
||||||
argslist.append("-" + "v"*verbosity)
|
argslist.append("-" + "v"*verbosity)
|
||||||
else:
|
else:
|
||||||
argslist.append("-q")
|
argslist.append("-q")
|
||||||
|
|
||||||
args = self.cli.parse_args(argslist)
|
args = self.cli.parse_args(argslist)
|
||||||
|
|
||||||
_outpipe = StringIO()
|
_outpipe = StringIO()
|
||||||
|
@ -769,12 +840,12 @@ class GUI(object):
|
||||||
|
|
||||||
if _status is False:
|
if _status is False:
|
||||||
_msg = f"Arguments failed! GeckoLoader couldn't execute the job\n\nArgs: {args.__repr__()}\n\nstderr: {self._remove_ansi(_errpipe.getvalue())}"
|
_msg = f"Arguments failed! GeckoLoader couldn't execute the job\n\nArgs: {args.__repr__()}\n\nstderr: {self._remove_ansi(_errpipe.getvalue())}"
|
||||||
self.ui.responses.appendPlainText(_outpipe.getvalue() + "\n\n" + _msg.strip() + "\n")
|
self.ui.responses.appendPlainText(_msg.strip() + "\n")
|
||||||
else:
|
else:
|
||||||
for line in self._remove_ansi(_outpipe.getvalue()).split("\n"):
|
for line in self._remove_ansi(_outpipe.getvalue()).split("\n"):
|
||||||
_msg += line.lstrip() + "\n"
|
_msg += line.lstrip() + "\n"
|
||||||
self.ui.responses.appendPlainText(_msg.strip() + "\n")
|
self.ui.responses.appendPlainText(_msg.strip() + "\n")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
datapath = Path.home() / ".GeckoLoader"
|
datapath = Path.home() / ".GeckoLoader"
|
||||||
|
@ -783,7 +854,7 @@ class GUI(object):
|
||||||
|
|
||||||
if not datapath.is_dir():
|
if not datapath.is_dir():
|
||||||
datapath.mkdir()
|
datapath.mkdir()
|
||||||
|
|
||||||
self.app = QtWidgets.QApplication(sys.argv)
|
self.app = QtWidgets.QApplication(sys.argv)
|
||||||
self.default_qtstyle = self.app.style().objectName()
|
self.default_qtstyle = self.app.style().objectName()
|
||||||
self.ui = MainWindow(self.version)
|
self.ui = MainWindow(self.version)
|
||||||
|
@ -808,8 +879,10 @@ class GUI(object):
|
||||||
self.ui.show()
|
self.ui.show()
|
||||||
sys.exit(self.app.exec_())
|
sys.exit(self.app.exec_())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli = GeckoLoaderCli('GeckoLoader', __version__, description='Dol editing tool for allocating extended codespace')
|
cli = GeckoLoaderCli('GeckoLoader', __version__,
|
||||||
|
description='Dol editing tool for allocating extended codespace')
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
cli.print_splash()
|
cli.print_splash()
|
||||||
|
|
12
main_ui.py
12
main_ui.py
|
@ -1,17 +1,7 @@
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import pickle as cPickle
|
|
||||||
import re
|
|
||||||
import signal
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from children_ui import PrefWindow
|
from children_ui import PrefWindow
|
||||||
from dolreader import DolFile
|
|
||||||
from fileutils import resource_path
|
from fileutils import resource_path
|
||||||
from kernel import CodeHandler, KernelLoader
|
|
||||||
|
|
||||||
class MainWindow(QtWidgets.QMainWindow):
|
class MainWindow(QtWidgets.QMainWindow):
|
||||||
def __init__(self, version: str):
|
def __init__(self, version: str):
|
||||||
|
@ -66,7 +56,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
font.setWeight(42)
|
font.setWeight(42)
|
||||||
self.setFont(font)
|
self.setFont(font)
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(QtGui.QPixmap(str(resource_path(os.path.join("bin", "icon.ico")))), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon.addPixmap(QtGui.QPixmap(str(resource_path("bin/icon.ico"))), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.setWindowIcon(icon)
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
#Top level widget
|
#Top level widget
|
||||||
|
|
Reference in a new issue