feat: add device and emulator screens

Change replaces Options and groups every option by intent. Device chooses --target or --every-board, the board read on the device or named by the card first and chosen. Emulators ticks --emulator. From a pack and Without the internet are rows of their own. Parity tests install the screen's argv and the flag's into two folders and compare dest and sha1.
This commit is contained in:
Abdessamad Derraz committed 2026-11-11 10:44:02 +01:00
1 parent 2e02c55102
commit b9481977e1
48 files changed
+2433 -579

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
# the site's build rewrites this line there (scripts/sitebootstrap.py).
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
$defaultInstallSha256 = "37442a7c0d307b0b95a40d7630cf57025a6498fea6223076892371b2d6363147"
$defaultInstallSha256 = "18fcbf04ff9dcd56e0bb3c61267b8051aa2c2c5ad22bfe73e7f767d4f7fde84b"
# The pin above refuses any changed byte: this cap only stops a body that
# cannot be the installer (a sign-in portal's page) before it is hashed.
$maximumInstallerBytes = 8MB
+407 -65
View File
@@ -18622,6 +18622,22 @@ class TuiState:
# Opened on the plan of the one setup found: its Change where row
# goes back to the setups.
self.opened_on_plan: bool = False
# The device chosen on Device (--target, "" for the board the run
# reads itself) or every board (--every-board), the emulators
# ticked on Emulators (--emulator), and the packs read in place of
# the network (--from-pack).
self.target: str = ""
self.every_board: bool = False
self.emulators: list[str] = []
self.packs: list[Path] = []
# The platform's board list, as fetched for Device: None until it
# comes or when it could not be read, and why.
self.targets: dict | None = None
self.targets_for: str = ""
self.targets_problem: str = ""
# (platform, folder, board, applied, here) of the last board event:
# kept across checks, a --target chosen since stops the event.
self.board_seen: tuple | None = None
@property
def screen(self) -> str:
@@ -19064,6 +19080,12 @@ def _tui_system_flags(state: TuiState) -> list[tuple[str, str | None]]:
def tui_flags(state: TuiState) -> list[tuple[str, str | None]]:
"""The options that carry the choices made on screen, CLI ones included."""
flags = list(state.passthrough)
if state.target:
flags.append(("--target", state.target))
if state.every_board:
flags.append(("--every-board", None))
flags += [("--emulator", name) for name in state.emulators]
flags += [("--from-pack", str(pack)) for pack in state.packs]
flags += _tui_system_flags(state)
flags += [("--core", name) for name in tui_core_flags(state)]
if state.regions:
@@ -19202,7 +19224,7 @@ class TuiRow(NamedTuple):
# Screens that scroll text instead of listing rows.
_PAGERS = ("preview", "command", "result", "misplaced", "unreadable", "games", "details")
_CHECKLISTS = ("systems", "cores")
_CHECKLISTS = ("systems", "cores", "emulators")
def _needed(row: dict) -> int:
@@ -19476,6 +19498,14 @@ def tui_rows(state: TuiState) -> list[TuiRow]:
return _system_rows(state)
if screen == "options":
return _option_rows(state)
if screen == "device":
return _device_rows(state)
if screen == "emulators":
needle = state.filters.get(screen, "")
return [_filter_row(state)] + [
TuiRow("emulator", f"[{'x' if name in state.emulators else ' '}] {name}",
value=name) for name in tui_emulators(state) if _matches(name, needle)
] + _REGIONS_END
if screen == "regions":
known = sorted(set(tui_choices(state)["regions"]) | set(state.cli_regions),
key=region_title)
@@ -19580,10 +19610,10 @@ def _plan_rows(state: TuiState) -> list[TuiRow]:
rows = [TuiRow("systems", TUI_SYSTEMS_ROW)]
game_data = _game_data_row(state)
return rows + ([game_data] if game_data is not None else []) + [
*_details_row(state), TuiRow("options", "Options"), TuiRow("quit", "Quit")]
*_details_row(state), TuiRow("options", "Change"), TuiRow("quit", "Quit")]
if not (_needed(check) if check else 0) and not check.get("data_missing"):
return [TuiRow("close", "Close"), *_games_rows(state), *_record_rows(state),
*_where_rows(state), *_details_row(state), TuiRow("options", "Options")]
*_where_rows(state), *_details_row(state), TuiRow("options", "Change")]
# The size the headline says: "Install 6.6 GB" stood under "14930 files
# to download, 6.8 GB", the copies counted in one and the data files in
# the other.
@@ -19639,7 +19669,7 @@ def _plan_rows(state: TuiState) -> list[TuiRow]:
rows.append(TuiRow("misplaced", "Show the files in the wrong place"))
if state.unreadable:
rows.append(TuiRow("unreadable", "Show the files that could not be read"))
return rows + [*_where_rows(state), *_details_row(state), TuiRow("options", "Options"),
return rows + [*_where_rows(state), *_details_row(state), TuiRow("options", "Change"),
TuiRow("quit", "Quit")]
@@ -19904,8 +19934,11 @@ _REGIONS_END = [TuiRow("none", "None"), TuiRow("done", "Done")]
def _first_item(state: TuiState) -> int:
"""The row a list of ticks opens on: its first item."""
return next((i for i, row in enumerate(tui_rows(state)) if row.action in TUI_TICK_ROWS), 0)
"""The row a list of ticks opens on: its first item. Elsewhere the
first row that is no heading."""
rows = tui_rows(state)
return next((i for i, row in enumerate(rows) if row.action in TUI_TICK_ROWS),
next((i for i, row in enumerate(rows) if row.action != "heading"), 0))
def _shared_needed(state: TuiState) -> dict[str, tuple[int, int]]:
@@ -19930,56 +19963,168 @@ def _yes(value: bool) -> str:
return "yes" if value else "no"
# The Change screen's groups, in the order they are drawn: a heading is no
# row Up and Down stop on, and a group with no row is not drawn.
TUI_CHANGE_GROUPS = ("What to install", "Where", "For which device", "How", "See")
def _option_rows(state: TuiState) -> list[TuiRow]:
"""The Change screen: every option one level below the plan, grouped by
what it decides, each row with its value and its flag."""
manifest = state.manifest or {}
choices = tui_choices(state)
rows = []
what: list[TuiRow] = []
if choices["regions"]:
rows.append(TuiRow("regions", "Preferred regions: "
what.append(TuiRow("regions", "Preferred regions: "
+ (", ".join(map(region_title, state.regions)) or "any"),
"--region"))
if manifest.get("categorized"):
# "Leave out game data: no" was a double negative.
rows.append(TuiRow("game_data", "Game data: "
+ ("left out" if state.no_game_data else "kept"),
"--no-game-data"))
found = len(state.facts.get("cores", []))
if _cores_dir_given(state):
rows.append(TuiRow("installed", "Installed cores only: yes, implied by --cores-dir",
"--cores-dir"))
elif state.platform in CORE_PLATFORMS and "system_cores" in manifest and found:
rows.append(TuiRow("installed", f"Installed cores only: "
f"{_yes(state.installed_only)} ({found} found)",
"--installed-cores"))
if len(choices["cores"]) > 1:
# The plan's words, the noun left to the row's own label. A list
# with one core asks nothing, as line mode does not.
rows.append(TuiRow("cores", "Cores: " + cores_words(
what.append(TuiRow("cores", "Cores: " + cores_words(
tui_cores_ticked(state), len(_core_base(state))).replace(" cores", ""), "--core"))
if "system_cores" in manifest and tui_emulators(state):
what.append(TuiRow("emulators", f"Emulators: {_emulator_words(state)}",
"--emulator"))
if manifest.get("categorized"):
# "Leave out game data: no" was a double negative.
what.append(TuiRow("game_data", "Game data: "
+ ("left out" if state.no_game_data else "kept"),
"--no-game-data"))
copied = ", ".join(str(folder) for folder in state.from_folders) or "none"
if manifest.get("save_directory"):
# The interface said "Name it with --save-dir" and had no row for it.
rows.append(TuiRow("savedir", f"Save folder: {_save_folder_words(state)}",
"--save-dir", style="path"))
if not LOCAL.offline:
# From a pack, or offline, nothing is downloaded.
rows.append(TuiRow("jobs", f"Parallel downloads: {state.jobs}", "--jobs"))
rows += [
where = [
# The plan's folder: AmberELEC's read the games part here and its
# bios folder on the plan, two values under one name. --dest stays the
# games part, as the command line takes it.
TuiRow("folder", "BIOS folder: "
+ _short_path(_plan_folder(state, state.dest), state.home),
"--dest", style="path"),
TuiRow("from", f"Copy from: {copied}", "--from", style="path"),
*([TuiRow("addapp", f"Put RetroBIOS on this card: {_yes(state.add_app)}",
"--add-app")] if _tui_app_ready(state) else []),
TuiRow("preview", "Preview the file list", "--dry-run"),
TuiRow("command", "Show the command line"),
]
if manifest.get("save_directory"):
# The interface said "Name it with --save-dir" and had no row for it.
where.append(TuiRow("savedir", f"Save folder: {_save_folder_words(state)}",
"--save-dir", style="path"))
where += [TuiRow("from", f"Copy from: {copied}", "--from", style="path"),
TuiRow("pack", "From a pack: "
+ (state.packs[0].name if state.packs else "none"), "--from-pack")]
device: list[TuiRow] = []
if state.platform in TARGET_PLATFORMS:
device.append(TuiRow("device", f"Device: {_device_words(state)}", "--target"))
found = len(state.facts.get("cores", []))
if _cores_dir_given(state):
device.append(TuiRow("installed", "Installed cores only: yes, implied by --cores-dir",
"--cores-dir"))
elif state.platform in CORE_PLATFORMS and "system_cores" in manifest and found:
device.append(TuiRow("installed", f"Installed cores only: "
f"{_yes(state.installed_only)} ({found} found)",
"--installed-cores"))
if _tui_app_ready(state):
device.append(TuiRow("addapp", f"Put RetroBIOS on this card: {_yes(state.add_app)}",
"--add-app"))
# Parallel downloads below: the row goes once nothing is downloaded,
# and the focus stays on the row just changed.
how = [TuiRow("offline", "Without the internet: "
+ ("yes, a pack is read" if LOCAL.pack is not None
else _yes(offline_requested())), "--offline")]
if not LOCAL.offline:
# From a pack, or offline, nothing is downloaded.
how.append(TuiRow("jobs", f"Parallel downloads: {state.jobs}", "--jobs"))
see = [TuiRow("preview", "Preview the file list", "--dry-run"),
TuiRow("command", "Show the command line")]
rows: list[TuiRow] = []
for heading, group in zip(TUI_CHANGE_GROUPS, (what, where, device, how, see)):
if group:
rows += [TuiRow("heading", heading, style="head"), *group]
return rows
def tui_emulators(state: TuiState) -> list[str]:
"""The emulators Emulators lists: each profile once, by the name the
list gives it, as --list-emulators names them."""
if state.manifest is None:
return []
return sorted(set(emulator_names(state.manifest, *tui_run_files(state)).values()))
def _emulator_words(state: TuiState) -> str:
"""The emulators chosen, as the Change row says them."""
if not state.emulators:
return "all"
if len(state.emulators) <= 2:
return ", ".join(state.emulators)
return f"{len(state.emulators)} chosen"
def _board_seen(state: TuiState) -> tuple[str, bool, bool] | None:
"""(board, applied, here) the last check read for this setup and folder."""
seen = state.board_seen
if seen is None or seen[:2] != (state.platform, state.dest):
return None
return seen[2], seen[3], seen[4]
def _board_where(here: bool) -> str:
return "this device" if here else "named by the card"
def _device_choice(state: TuiState) -> str:
"""The board the runs install for, "" for every board."""
if state.every_board:
return ""
if state.target:
return state.target
seen = _board_seen(state)
return seen[0] if seen is not None and seen[1] else ""
def _device_words(state: TuiState) -> str:
"""The device as the Change row says it: the board, where the run read
it when it chose it itself."""
chosen = _device_choice(state)
if not chosen:
return "every board"
seen = _board_seen(state)
if not state.target and seen is not None:
return f"{chosen}, {_board_where(seen[2])}"
return chosen
def _device_rows(state: TuiState) -> list[TuiRow]:
"""Device: the platform's boards by the names its list gives them, the
one read here or named by the card first, then every board."""
targets = state.targets if state.targets_for == state.platform else None
if not targets:
return []
seen = _board_seen(state)
chosen = _device_choice(state)
names = sorted(targets)
if seen is not None and seen[0] in targets:
names.remove(seen[0])
names.insert(0, seen[0])
rows = []
for name in names:
images = [str(image) for image in targets[name].get("images") or ()]
# The device names an image carries say what a board code means.
right = (_board_where(seen[2]) if seen is not None and name == seen[0]
else ", ".join(images))
narrow = (images[0] + (f" +{len(images) - 1}" if len(images) > 1 else ""),) \
if images and right != images[0] and name != (seen or ("",))[0] else ()
rows.append(TuiRow("board", f"({'x' if name == chosen else ' '}) {name}", right,
name, narrow=narrow))
rows.append(TuiRow("board", f"({' ' if chosen else 'x'}) Every board", value=""))
return rows
def _choose_board(state: TuiState, name: str) -> list[tuple]:
"""A board chosen on Device, back on Change. The board the run reads
itself is no option: the command stays the one with nothing chosen."""
seen = _board_seen(state)
read = seen[0] if seen is not None and seen[1] else ""
state.target = "" if name == read else name
state.every_board = not name and bool(read)
return _back(state)
def _save_dir_given(state: TuiState) -> Path | None:
return next((Path(value) for flag, value in state.passthrough
if flag == "--save-dir" and value), None)
@@ -20183,15 +20328,19 @@ def _tui_record_take(state: TuiState) -> None:
state.games_folder = parsed.for_games if isinstance(parsed.for_games, Path) else None
state.required_only = bool(parsed.required_only) and state.for_games
state.games_choice = "record"
# Device and Emulators show these: a choice no row showed was kept apart.
state.target = str(parsed.target or "")
state.every_board = bool(parsed.every_board)
state.emulators = list(parsed.emulator or [])
state.record_flags = [(flag, value) for flag, value in record_options(setup["choice"])
if flag in ("--target", "--emulator", "--every-board",
"--declared-only")]
if flag == "--declared-only"]
def _tui_record_drop(state: TuiState) -> None:
"""The recorded choice given up: the choice nothing narrows."""
state.cli_systems, state.cores, state.regions, state.record_flags = [], [], [], []
state.no_game_data = state.installed_only = state.required_only = False
state.target, state.every_board, state.emulators = "", False, []
state.for_games, state.games_folder, state.games_choice = None, None, ""
# The systems of the recorded check go, and with them its ticks.
state.systems, state.ticked, state.keep_ticked, state.widened_from = [], set(), None, None
@@ -20575,10 +20724,13 @@ def _os_folder(path: Path, folder: Path) -> bool:
def _browse_to(state: TuiState, folder: Path | None, came_from: Path | None = None) -> None:
state.browse_dir = folder
copying = state.browse_for == "from"
state.browse_rows, state.status = _browse_rows(folder, copying,
state.browse_rows, state.status = _browse_rows(folder, copying or state.browse_for == "pack",
_dest_card(state) if copying else None)
if state.browse_for == "pack":
# A pack is a ZIP, never a folder.
state.browse_rows = [row for row in state.browse_rows if row.action != "use"]
focus = 0
if (folder is not None and state.browse_for != "from"
if (folder is not None and state.browse_for not in ("from", "pack")
and folder in (state.home, Path(folder.anchor))):
# No frontend reads its BIOS files from HOME or a drive's root: A
# pressed through the screens installed into ~. A goes into a
@@ -20791,6 +20943,9 @@ def _activate(state: TuiState, row: TuiRow) -> list[tuple]:
state.path_selected = bool(state.path_text)
return _push(state, "path")
if screen == "browse":
if action == "zip" and state.browse_for == "pack":
# Opened in this process (perform), which answers pack_opened.
return [("pack", row.value)]
if action == "use" and state.browse_for == "save":
state.passthrough = [flag for flag in state.passthrough
if flag[0] != "--save-dir"]
@@ -20913,6 +21068,8 @@ def _activate(state: TuiState, row: TuiRow) -> list[tuple]:
return _checklist(state, row)
if screen == "options":
return _option(state, action, 0)
if screen == "device" and action == "board":
return _choose_board(state, str(row.value))
if screen == "confirm":
if action == "install":
state.stack.pop()
@@ -20959,6 +21116,10 @@ def _checklist(state: TuiState, row: TuiRow) -> list[tuple]:
state.cores, state.no_cores = [], False
elif action == "none" and screen == "regions":
state.regions = []
elif action == "none" and screen == "emulators":
# None ticked installs for every emulator, as Preferred regions keeps
# every region with none ticked.
state.emulators = []
elif action == "none":
if screen == "systems":
state.ticked = set()
@@ -21437,6 +21598,21 @@ def _option(state: TuiState, action: str, step: int) -> list[tuple]:
state.jobs = max(1, min(32, state.jobs + (step or 1)))
elif action == "addapp":
state.add_app = step > 0 if step else not state.add_app
elif action == "offline" and LOCAL.pack is None:
# Set in this process by the effect, as --offline sets it: the
# runs started next inherit it, and their command names it.
return [("offline", step > 0 if step else not offline_requested())]
elif action == "device":
_push(state, "device")
state.focus["device"] = _device_focus(state)
if state.targets_for != state.platform:
state.targets, state.targets_problem = None, ""
return [("targets", state.platform)]
elif action == "emulators":
_push(state, action)
state.focus[action] = _first_item(state)
elif action == "pack":
return _open_pack_browser(state)
elif action == "cores":
# On the first core: the filter row under A opened a field a
# controller cannot type into.
@@ -21468,6 +21644,54 @@ def _option(state: TuiState, action: str, step: int) -> list[tuple]:
return []
def _device_focus(state: TuiState) -> int:
"""Device opens on the board chosen: the one read here or named by
the card when nothing else was."""
rows = _device_rows(state)
chosen = _device_choice(state)
return next((index for index, row in enumerate(rows) if row.value == chosen), 0)
def _open_pack_browser(state: TuiState) -> list[tuple]:
"""The browser, to name a pack downloaded before: it opens where a
download lands."""
state.browse_for = "pack"
_push(state, "browse")
downloads = state.home / "Downloads"
start = (state.packs[0].parent if state.packs
else downloads if _is_dir(downloads) else state.home)
_browse_to(state, _nearest_folder(start))
return []
def open_tui_pack(path: Path, plat: str) -> str:
"""The pack the screen chose, opened in this process in place of the
network as --from-pack opens it: "" once it is, else why not."""
try:
pack = PackSource([path])
except ValueError as exc:
return str(exc)
spelled = pack.platforms()
if spelled and plat not in spelled:
pack.close()
return (f"{pack.name} is a pack for "
f"{' and '.join(display_name(name) for name in spelled)}, "
f"not {display_name(plat)}.")
if LOCAL.pack is not None:
LOCAL.pack.close()
LOCAL.pack = pack
return ""
def set_offline(on: bool) -> None:
"""Without the internet on or off for this process and the runs it
starts, as --offline sets it."""
if on:
os.environ[OFFLINE_VARIABLE] = OFFLINE_FLAG_VALUE
else:
os.environ.pop(OFFLINE_VARIABLE, None)
def _open_from_browser(state: TuiState) -> list[tuple]:
"""The browser, to name an old card, a backup or a ZIP to copy from."""
state.browse_for = "from"
@@ -21546,10 +21770,18 @@ def _tick(state: TuiState, row: TuiRow, on: bool | None) -> None:
chosen = state.ticked
elif state.screen == "cores" and row.action == "core":
chosen = {name for name in tui_choices(state)["cores"] if core_ticked(state, name)}
elif state.screen == "emulators" and row.action == "emulator":
chosen = set(state.emulators)
else:
return
value = row.value
want = (value not in chosen) if on is None else on
if state.screen == "emulators":
if want and value not in state.emulators:
state.emulators.append(str(value))
elif not want and value in state.emulators:
state.emulators.remove(str(value))
return
if state.screen == "systems":
if want:
state.ticked.add(value)
@@ -21793,7 +22025,9 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]:
elif name in ("esc", "backspace"):
return _back(state)
elif (name == "tab" or char == "o") and screen in ("plan", "systems", "confirm"):
return _push(state, "options")
_push(state, "options")
state.focus["options"] = _first_item(state)
return []
elif char == "/" and any(item.action == "filter" for item in rows):
# The focus goes to the field typed into: it stayed on None, and the
# bar named None's keys while letters went into the filter.
@@ -21808,7 +22042,7 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]:
elif screen == "regions" and name in ("right", "shift-down"):
_move_region(state, row.value, 1)
return []
elif screen in _CHECKLISTS and row.action in ("system", "core") and (
elif screen in _CHECKLISTS and row.action in ("system", "core", "emulator") and (
char == " " or name in ("right", "left")):
_tick(state, row, None if char == " " else name == "right")
return []
@@ -21822,12 +22056,21 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]:
return _checklist(state, named[0]) if named else []
elif screen == "options" and name in ("left", "right"):
return _option(state, row.action, 1 if name == "right" else -1) \
if row.action in ("game_data", "installed", "jobs", "addapp") \
if row.action in ("game_data", "installed", "jobs", "addapp", "offline") \
or (row.action == "from" and name == "left") else []
elif char == " ":
return _space(state, row)
elif name == "enter":
return _activate(state, row)
if rows[focus].action == "heading":
# A heading names the rows under it and is never in focus: the
# move goes on to the next row its way, else stays where it was.
step = -1 if name in ("up", "pgup", "end") or char in ("k", "G") else 1
order = list(range(focus, -1, -1) if step < 0 else range(focus, len(rows)))
if wrap:
order += range(last, focus, -1) if step < 0 else range(0, focus)
focus = next((index for index in order if rows[index].action != "heading"),
max(0, min(state.focus.get(screen, 0), last)))
state.focus[screen] = focus
return []
@@ -21906,6 +22149,8 @@ def tui_mouse(state: TuiState, event: TuiMouse) -> list[tuple]:
screen = state.screen
row = rows[index]
seen = (screen, len(state.stack), row.action, row.value)
if row.action == "heading":
return []
if state.editing:
state.editing = ""
elif row.action in TUI_TICK_ROWS:
@@ -21929,7 +22174,7 @@ def tui_mouse(state: TuiState, event: TuiMouse) -> list[tuple]:
# The rows a tap ticks or unticks, as Space does: the lists of ticks.
TUI_TICK_ROWS = ("system", "core", "region")
TUI_TICK_ROWS = ("system", "core", "region", "emulator")
def _bar_commits(state: TuiState, key: TuiKey) -> bool:
@@ -22069,7 +22314,12 @@ def _wheel(state: TuiState, hits: TuiHits, step: int) -> list[tuple]:
state.list_top[screen] = top
rows = tui_rows(state)
focus = max(0, min(state.focus.get(screen, 0), len(rows) - 1))
state.focus[screen] = max(top, min(focus, top + shown - 1))
focus = max(top, min(focus, top + shown - 1))
if rows and rows[focus].action == "heading":
# Never on a heading: the row under it, else the one above.
below = focus + 1 < min(len(rows), top + shown)
focus = focus + 1 if below or focus == 0 else focus - 1
state.focus[screen] = focus
elif hits.scroll == "error":
state.focus["error_text"] = max(0, state.focus.get("error_text", 0) + lines)
elif hits.scroll == "pager":
@@ -22170,6 +22420,10 @@ def _take_event(state: TuiState, event: dict) -> None:
state.set_aside = set(event["dests"])
elif kind == "board" and state.run == "check":
state.board = str(event["message"])
# Read on the device itself, or named by the card in a reader: a
# computer preparing a card has no board of its own.
state.board_seen = (state.platform, state.dest, str(event["board"]),
bool(event["applied"]), detect_board(state.platform) is not None)
elif kind == "version" and state.run == "check":
state.version = str(event["message"])
state.version_short = (f"List for {display_name(state.platform, state.manifest)} "
@@ -22239,6 +22493,29 @@ def tui_receive(state: TuiState, message: tuple) -> list[tuple]:
if state.games_probed is None:
state.games_probed = (plat, state.dest)
return _start_run(state, "check")
if kind == "targets":
_kind, plat, targets, problem = message
if plat == state.platform:
state.targets, state.targets_for, state.targets_problem = targets, plat, problem
if state.screen == "device":
state.focus["device"] = _device_focus(state)
return []
if kind == "pack_opened":
_kind, path, problem = message
if state.screen != "browse" or state.browse_for != "pack":
return []
if problem:
state.status = _styled(problem, "refusal")
return []
# The pack's own list, as --from-pack reads it: the list fetched
# before is fetched again from the pack.
state.packs = [path]
state.browse_for = "dest"
state.manifest, state.manifest_for = None, ""
if not state.manifest_given:
state.manifest_path = None
state.targets_for = ""
return _start_check(state)
if kind == "app":
# Put from the result screen, in this process.
state.app, state.app_running = message[1], False
@@ -22414,6 +22691,8 @@ _ROW_VERBS = {
"cardsystem": "Choose", "rescan": "Look again", "elsewhere": "Choose", "drive": "Choose",
"recheck": "Check again", "gamedata": "Change", "share": "Choose", "morecores": "Show",
"games": "Change", "startonly": "Change", "gameslist": "Show", "details": "Show",
"device": "Open", "emulators": "Open", "emulator": "Tick", "board": "Choose",
"pack": "Choose", "offline": "Change",
}
@@ -22423,6 +22702,9 @@ TUI_ROW_SPREAD = 78
def _row_line(row: TuiRow, focused: bool, width: int) -> TuiLine:
if row.action == "heading":
# Flush left of the rows it names, never in focus.
return _styled(fit(row.label, width), row.style)
left = ("> " if focused else " ") + row.label
if row.align and (row.right or row.narrow or row.cut):
# One column for the list: the longest form that fits after it, a
@@ -22901,7 +23183,7 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list:
lines += _unavailable_brief(state) + _details(_unavailable_lines(state))
if check is state.check:
lines += _unplaced_lines(_choice_summary(state), state,
"Choose it in Options, Save folder (--save-dir).")
"Choose it in Change, Save folder (--save-dir).")
if check is state.check:
lines += _found_lines(state)
if check is state.check and state.from_folders:
@@ -23193,10 +23475,13 @@ def _view_browse(state: TuiState, width: int, height: int) -> tuple:
elif state.browse_for == "save":
hint = [f"Choose {display_name(state.platform)}'s save directory: some "
"cores read files there."]
elif state.browse_for == "pack":
hint = ["Choose the pack ZIP downloaded before: nothing is downloaded then."]
# The hint is kept whole under the list, which scrolls: three folders at
# 40x12 cut it to "Choose the old card, a backup folder".
return ("Copy from" if state.browse_for == "from"
else "Save folder" if state.browse_for == "save" else "Browse for a folder",
else "Save folder" if state.browse_for == "save"
else "From a pack" if state.browse_for == "pack" else "Browse for a folder",
_compose(state, width, height, [where], tui_rows(state), _status_after(state),
hint),
("A/Enter Open", "B/Esc Back", "? Help"))
@@ -23489,7 +23774,7 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple:
name = display_name(state.platform, state.manifest)
return (f"{system} ({name} files)" if system and system != name else name,
_plan_body(state, width, height, lines, rows),
("A/Enter Install", "B/Esc Back", "Y/o Options", "? Help"))
("A/Enter Install", "B/Esc Back", "Y/o Change", "? Help"))
def _plan_body(state: TuiState, width: int, height: int, lines: list,
@@ -23678,13 +23963,13 @@ def _view_systems(state: TuiState, width: int, height: int) -> tuple:
def _view_options(state: TuiState, width: int, height: int) -> tuple:
rows = tui_rows(state)
before = ["Each row is an option of the command line, named on the right."]
# The headings say what each group decides, the flags on the right
# which option of the command line each row is.
after: list = []
if width < 60:
# A value cut to make room for its flag said nothing: the flag of
# the focused row is named below instead.
focus = rows[min(state.focus.get("options", 0), len(rows) - 1)]
before = []
after = [f"Sets {focus.right}"] if focus.right else []
rows = [row._replace(right="") for row in rows]
# A folder is cut in its middle, its last levels being what tells it apart.
@@ -23692,10 +23977,35 @@ def _view_options(state: TuiState, width: int, height: int) -> tuple:
rows = [_middle_label(row, room) if row.style == "path" else row for row in rows]
if state.status:
after.append(state.status)
return ("Options", _compose(state, width, height, before, rows, after),
return ("Change", _compose(state, width, height, [], rows, after),
("A/Enter Change", "B/Esc Back", "Left/Right Set", "? Help"))
def _view_device(state: TuiState, width: int, height: int) -> tuple:
# "Board" is the list's word, glossed once: a beginner knows the device.
pinned = ["Choose the board, the chip of the device the games run on. "
"Every board fits any device."]
rows = tui_rows(state)
if state.targets_for != state.platform:
after = ["Reading the board list..."]
elif not rows:
after = [state.targets_problem or f"{display_name(state.platform)} publishes "
"no board list: every board's files are installed."]
else:
after = []
return ("Device", _compose(state, width, height, [], rows, after,
_status_footer(state), pinned),
("A/Enter Choose", "B/Esc Back", "? Help") if rows else ("B/Esc Back", "? Help"))
def _view_emulators(state: TuiState, width: int, height: int) -> tuple:
pinned = ["Tick the emulators to install for. With none ticked, every "
"emulator's files are installed."]
return ("Emulators", _compose(state, width, height, [], tui_rows(state), [],
_status_footer(state), pinned),
_CHECKLIST_BAR)
def _middle_label(row: TuiRow, room: int) -> TuiRow:
"""A row naming a folder, the folder cut in its middle to fit."""
name, _sep, value = row.label.partition(": ")
@@ -24399,6 +24709,7 @@ _TUI_VIEWS: dict[str, Callable[[TuiState, int, int], tuple]] = {
"installing": _view_installing, "result": _view_result, "error": _view_error,
"quit": _view_quit, "cardroot": _view_cardroot, "misplaced": _view_misplaced,
"unreadable": _view_unreadable, "games": _view_games, "details": _view_details,
"device": _view_device, "emulators": _view_emulators,
}
@@ -24446,22 +24757,22 @@ def _help_lines(state: TuiState) -> list[tuple[str, str]]:
# How a tap acts, before what the list says elsewhere: last, it was the
# line a 40x12 help cut.
keys += _tap_help(state)
if screen in _CHECKLISTS:
if screen in ("systems", "cores"):
keys.append(("a, n", "All, none"))
elif screen == "regions":
elif screen in ("regions", "emulators"):
keys.append(("n", "None"))
if screen == "platforms":
keys.append(("/", "Filter by setup or device name"))
elif screen in ("systems", "cores"):
elif screen in _CHECKLISTS:
keys.append(("/", "Filter"))
if screen in ("platforms", "systems", "cores") and state.filters.get(screen):
if screen in ("platforms", *_CHECKLISTS) and state.filters.get(screen):
keys.append((names["esc"], "Clear the filter"))
if screen == "regions":
keys.append(("Left/Right", "Move a region up or down the order"))
if screen == "options":
keys.append(("Left/Right", "Change a value"))
if screen in ("plan", "systems", "confirm"):
keys.append((names["options"], "Options"))
keys.append((names["options"], "Change"))
if screen in ("plan", "confirm"):
keys.append(("d", "Details"))
elif screen == "result" and not tui_rows(state):
@@ -24510,6 +24821,8 @@ def _primary(state: TuiState) -> str | None:
verb = _ROW_VERBS.get(row.action)
if row.action == "filter" and _only_match(state) is not None:
verb = "Choose"
if row.action == "zip" and state.browse_for == "pack":
verb = "Use this pack"
return f"A/Enter {verb}" if verb else None
@@ -24544,7 +24857,7 @@ def _view_help(state: TuiState, width: int, height: int) -> tuple:
# Cut from its end at 40x12, the help lost Quit and This help with no
# sign: what a list's keys also say elsewhere goes first.
for spare in ("First, last", "All, none", "extra", "Filter by setup or device name",
"Filter", "Options", "Details", "This help", "gap", "definitions"):
"Filter", "Change", "Details", "This help", "gap", "definitions"):
if (len(drawn(keys)) + len(extra) + len(defined)
+ len(_text_lines(more, width)) <= height):
break
@@ -24752,17 +25065,13 @@ def tell_apart(setups: list[tuple]) -> list[tuple]:
def _tui_passthrough(args: argparse.Namespace) -> list[tuple[str, str | None]]:
"""Options the screens do not change, handed to every run unchanged."""
flags: list[tuple[str, str | None]] = []
for flag in ("--target", "--romm-firmware"):
value = getattr(args, flag[2:].replace("-", "_"))
if value is not None:
flags.append((flag, str(value)))
if args.romm_firmware is not None:
flags.append(("--romm-firmware", str(args.romm_firmware)))
for flag in ("--save-dir", "--cores-dir"):
value = getattr(args, flag[2:].replace("-", "_"))
if value is not None:
flags.append((flag, str(Path(value).absolute())))
flags += [("--emulator", name) for name in args.emulator or []]
flags += [("--from-pack", str(Path(pack).absolute())) for pack in args.from_pack or []]
for flag in ("--every-board", "--standalone-copies", "--verbose"):
for flag in ("--standalone-copies", "--verbose"):
if getattr(args, flag[2:].replace("-", "_")):
flags.append((flag, None))
return flags
@@ -24843,6 +25152,10 @@ def tui_start(
state.jobs = args.jobs
state.add_app = bool(getattr(args, "add_app", False))
state.passthrough = _tui_passthrough(args)
state.target = str(args.target or "")
state.every_board = bool(args.every_board)
state.emulators = list(args.emulator or [])
state.packs = [Path(pack).absolute() for pack in args.from_pack or []]
if getattr(args, "for_games", None) is not None:
state.for_games, state.games_choice = True, "cli"
if isinstance(args.for_games, Path):
@@ -25102,6 +25415,21 @@ def _tui_fetch(plat: str, inbox: queue.Queue, log: io.StringIO) -> None:
inbox.put(("manifest_failed", plat, title, lines, 1))
def _tui_fetch_targets(plat: str, inbox: queue.Queue, log: io.StringIO) -> None:
"""The platform's board list for Device, fetched in this process as a
--target run reads it: the pack's or the list's beside --manifest, else
the network's. None and why when it cannot be read."""
mark = len(log.getvalue())
try:
targets = fetch_targets(plat)
except SystemExit:
targets = None
said = [line.strip() for line in log.getvalue()[mark:].splitlines() if line.strip()]
problem = "" if targets is not None else (
f"The board list could not be read{': ' + said[0] if said else '.'}")
inbox.put(("targets", plat, targets, problem))
def _tui_fetch_games(plat: str, inbox: queue.Queue, log: io.StringIO, dest: Path | None,
look: bool) -> None:
"""The file list, then, once it came, a look at the card for games
@@ -25405,7 +25733,7 @@ ROMM_SCAN_WORDS = ("RomM lists the firmware its library scan has recorded: start
# The result's remedy for the save files left out, as the terminal says it
# once the screen is gone: Options are not there to choose from
# Line mode's words.
TUI_SAVE_REMEDY = "Choose it in Options, Save folder (--save-dir), next time."
TUI_SAVE_REMEDY = "Choose it in Change, Save folder (--save-dir), next time."
LINE_SAVE_REMEDY = "Name it with --save-dir next time."
@@ -25533,12 +25861,19 @@ def run_tui(args: argparse.Namespace) -> int:
for run in current:
run.stop(0)
current.clear()
if not state.manifest_given and not args.from_pack and state.manifest:
if not state.manifest_given and not state.packs and state.manifest:
if state.platform not in written:
path = work / f"{state.platform}.json"
path.write_text(json.dumps(state.manifest), encoding="utf-8")
written[state.platform] = path
state.manifest_path = written[state.platform]
if state.targets_for == state.platform and state.targets:
# Beside the list, where a --target run without the
# internet reads the boards (local_targets).
boards = work / "targets" / f"{state.platform}.json"
boards.parent.mkdir(exist_ok=True)
boards.write_text(json.dumps(state.targets), encoding="utf-8")
written[f"targets:{state.platform}"] = boards
log = work / f"{effect[1]}.log"
if effect[1] == "install":
state.log = str(log)
@@ -25561,6 +25896,13 @@ def run_tui(args: argparse.Namespace) -> int:
elif kind == "app":
threading.Thread(target=_tui_put_app, args=(effect[1], inbox),
daemon=True).start()
elif kind == "targets":
threading.Thread(target=_tui_fetch_targets, args=(effect[1], inbox, buffer),
daemon=True).start()
elif kind == "pack":
inbox.put(("pack_opened", effect[1], open_tui_pack(effect[1], state.platform)))
elif kind == "offline":
set_offline(effect[1])
def on_interrupt(_signum: int, _frame: object) -> None:
flags["interrupt"] = True
+1 -1
View File
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
# curl or wget stop on a cut transfer before the hash is read: the site's
# build rewrites this line there (scripts/sitebootstrap.py).
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
DEFAULT_INSTALL_SHA256="37442a7c0d307b0b95a40d7630cf57025a6498fea6223076892371b2d6363147"
DEFAULT_INSTALL_SHA256="18fcbf04ff9dcd56e0bb3c61267b8051aa2c2c5ad22bfe73e7f767d4f7fde84b"
# The pin above refuses any changed byte: this cap only stops a body that
# cannot be the installer (a sign-in portal's page) before it is hashed.
MAX_INSTALLER_BYTES=8388608
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 1201450,
"sha256": "37442a7c0d307b0b95a40d7630cf57025a6498fea6223076892371b2d6363147",
"size": 1217065,
"sha256": "18fcbf04ff9dcd56e0bb3c61267b8051aa2c2c5ad22bfe73e7f767d4f7fde84b",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 1255075,
"sha256": "23393eb6b88f7a7875bd034e79c02d81e80409c9403290bb96a75166bf7a60b6"
"size": 1270690,
"sha256": "dbda647988b00ef42e70c82165cbbe8ea11fcfeec59ab8d753dfbfe7914e07cb"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 1201450,
"sha256": "37442a7c0d307b0b95a40d7630cf57025a6498fea6223076892371b2d6363147",
"size": 1217065,
"sha256": "18fcbf04ff9dcd56e0bb3c61267b8051aa2c2c5ad22bfe73e7f767d4f7fde84b",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 1201450,
"sha256": "37442a7c0d307b0b95a40d7630cf57025a6498fea6223076892371b2d6363147",
"size": 1217065,
"sha256": "18fcbf04ff9dcd56e0bb3c61267b8051aa2c2c5ad22bfe73e7f767d4f7fde84b",
"executable": false
},
{
@@ -1,14 +1,21 @@
RetroBIOS: Options
Each row is an option of the command line, named on the right.
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
@@ -24,13 +31,6 @@
@@ -1,12 +1,12 @@
RetroBIOS: Options
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
A Open B Back <> Set ? Help
@@ -1,15 +1,15 @@
RetroBIOS: Options
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
A Open B Back <> Set ? Help
@@ -1,24 +1,24 @@
RetroBIOS: Options
Each row is an option of the command line, named on the right.
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
A/Enter Open B/Esc Back Left/Right Set ? Help
+105 -23
View File
@@ -336,7 +336,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -366,7 +366,7 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -375,7 +375,7 @@
^[[0;7;35m > Close^[[0m
Details
Options
Change
@@ -407,7 +407,7 @@
^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -449,18 +449,25 @@
^[[0;1m ^[[0;1;35m2^[[0;1m of ^[[0;1;35m3^[[0;1m systems: ^[[0;1;35m4^[[0;1m files, ^[[0;1;35m1.0 MB^[[0m
^[[0;1;35mA/Enter^[[0m Tick ^[[0;2mB/Esc^[[0m Done ^[[0;2m?^[[0m Help
=== options
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Options^[[0m
=== change
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Change^[[0m
Each row is an option of the command line, named on the right.
^[[0;1m What to install^[[0m
^[[0;7;35m > Preferred regions: North America, Japan --region^[[0m
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
^[[0;1m Where^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m --dest
Copy from: none --from
From a pack: none --from-pack
^[[0;1m For which device^[[0m
Device: every board --target
Installed cores only: no (1 found) --installed-cores
^[[0;1m How^[[0m
Without the internet: no --offline
Parallel downloads: 8 --jobs
^[[0;1m See^[[0m
Preview the file list --dry-run
Show the command line
@@ -476,13 +483,6 @@
@@ -490,6 +490,88 @@
^[[0;1;35mA/Enter^[[0m Open ^[[0;2mB/Esc^[[0m Back ^[[0;2mLeft/Right^[[0m Set ^[[0;2m?^[[0m Help
=== device
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Device^[[0m
Choose the board, the chip of the device the games run on. Every board fits any device.
^[[0;7;35m > (x) h700 named by the card^[[0m
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
^[[0;1;35mA/Enter^[[0m Choose ^[[0;2mB/Esc^[[0m Back ^[[0;2m?^[[0m Help
=== emulators
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Emulators^[[0m
Tick the emulators to install for. With none ticked, every emulator's files are installed.
Filter (/ to type)
[ ] mesen
^[[0;7;35m > [x] pcsx_rearmed^[[0m
None
^[[0;32mDone^[[0m
^[[0;1;35mA/Enter^[[0m Tick ^[[0;2mB/Esc^[[0m Done ^[[0;2m?^[[0m Help
=== regions
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Preferred regions^[[0m
@@ -864,7 +946,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
@@ -914,7 +996,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -940,7 +1022,7 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -1077,7 +1159,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1104,4 +1186,4 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
+40 -14
View File
@@ -112,9 +112,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -124,10 +124,10 @@
^[[0;7;35m > Close^[[0m
Details
Options
Change
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -141,19 +141,45 @@
place
^[[0;1m ^[[0;1;35m2^[[0;1m of ^[[0;1;35m3^[[0;1m systems: ^[[0;1;35m4^[[0;1m files, ^[[0;1;35m1.0 MB^[[0m
^[[0;1;35mA^[[0m Tick ^[[0;2mB^[[0m Done ^[[0;2m?^[[0m Help
=== options
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Options^[[0m
=== change
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Change^[[0m
^[[0;1m What to install^[[0m
^[[0;7;35m > Preferred regions: North America, Ja^[[0m
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
^[[0;1m Where^[[0m
BIOS folder: ^[[0;1m~/.config...ch/system^[[0m
Copy from: none
Preview the file list
Show the command line
^[[0;2m 1-8 of 18^[[0m
^[[0;1;35mA^[[0m Open ^[[0;2mB^[[0m Back ^[[0;2m<>^[[0m Set ^[[0;2m?^[[0m Help
=== device
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Device^[[0m
Choose the board, the chip of the
device the games run on. Every board
fits any device.
^[[0;7;35m > (x) h700 named by the card^[[0m
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
^[[0;1;35mA^[[0m Choose ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help
=== emulators
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Emulators^[[0m
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
^[[0;7;35m > [x] pcsx_rearmed^[[0m
None
^[[0;32mDone^[[0m
^[[0;1;35mA^[[0m Tick ^[[0;2mB^[[0m Done ^[[0;2m?^[[0m Help
=== regions
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Preferred regions^[[0m
@@ -276,7 +302,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
@@ -296,7 +322,7 @@
Only what starts: no
Show the games
^[[0;2m 1-4 of 9^[[0m
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -348,4 +374,4 @@
Choose systems
Copy from an old card or a folder
^[[0;2m 1-4 of 8^[[0m
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
+51 -19
View File
@@ -137,11 +137,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -151,13 +151,13 @@
^[[0;7;35m > Close^[[0m
Details
Options
Change
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -174,22 +174,54 @@
place
^[[0;1m ^[[0;1;35m2^[[0;1m of ^[[0;1;35m3^[[0;1m systems: ^[[0;1;35m4^[[0;1m files, ^[[0;1;35m1.0 MB^[[0m
^[[0;1;35mA^[[0m Tick ^[[0;2mB^[[0m Done ^[[0;2m?^[[0m Help
=== options
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Options^[[0m
=== change
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Change^[[0m
^[[0;1m What to install^[[0m
^[[0;7;35m > Preferred regions: North America, Ja^[[0m
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
^[[0;1m Where^[[0m
BIOS folder: ^[[0;1m~/.config...ch/system^[[0m
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
^[[0;1m For which device^[[0m
Device: every board
^[[0;2m 1-11 of 18^[[0m
^[[0;1;35mA^[[0m Open ^[[0;2mB^[[0m Back ^[[0;2m<>^[[0m Set ^[[0;2m?^[[0m Help
=== device
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Device^[[0m
Choose the board, the chip of the
device the games run on. Every board
fits any device.
^[[0;7;35m > (x) h700 named by the card^[[0m
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
^[[0;1;35mA^[[0m Choose ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help
=== emulators
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Emulators^[[0m
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
^[[0;7;35m > [x] pcsx_rearmed^[[0m
None
^[[0;32mDone^[[0m
^[[0;1;35mA^[[0m Tick ^[[0;2mB^[[0m Done ^[[0;2m?^[[0m Help
=== regions
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Preferred regions^[[0m
@@ -339,7 +371,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
@@ -363,9 +395,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -427,6 +459,6 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Change ^[[0;2m?^[[0m Help
+73 -23
View File
@@ -208,7 +208,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -222,7 +222,7 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -231,7 +231,7 @@
^[[0;7;35m > Close^[[0m
Details
Options
Change
@@ -247,7 +247,7 @@
^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -273,31 +273,81 @@
^[[0;1m ^[[0;1;35m2^[[0;1m of ^[[0;1;35m3^[[0;1m systems: ^[[0;1;35m4^[[0;1m files, ^[[0;1;35m1.0 MB^[[0m
^[[0;1;35mA/Enter^[[0m Tick ^[[0;2mB/Esc^[[0m Done ^[[0;2m?^[[0m Help
=== options
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Options^[[0m
=== change
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Change^[[0m
Each row is an option of the command line, named on the right.
^[[0;1m What to install^[[0m
^[[0;7;35m > Preferred regions: North America, Japan --region^[[0m
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
^[[0;1m Where^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m --dest
Copy from: none --from
From a pack: none --from-pack
^[[0;1m For which device^[[0m
Device: every board --target
Installed cores only: no (1 found) --installed-cores
^[[0;1m How^[[0m
Without the internet: no --offline
Parallel downloads: 8 --jobs
^[[0;1m See^[[0m
Preview the file list --dry-run
Show the command line
^[[0;1;35mA/Enter^[[0m Open ^[[0;2mB/Esc^[[0m Back ^[[0;2mLeft/Right^[[0m Set ^[[0;2m?^[[0m Help
=== device
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Device^[[0m
Choose the board, the chip of the device the games run on. Every board fits
any device.
^[[0;7;35m > (x) h700 named by the card^[[0m
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
^[[0;1;35mA/Enter^[[0m Choose ^[[0;2mB/Esc^[[0m Back ^[[0;2m?^[[0m Help
=== emulators
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Emulators^[[0m
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (/ to type)
[ ] mesen
^[[0;7;35m > [x] pcsx_rearmed^[[0m
None
^[[0;32mDone^[[0m
^[[0;1;35mA/Enter^[[0m Tick ^[[0;2mB/Esc^[[0m Done ^[[0;2m?^[[0m Help
=== regions
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Preferred regions^[[0m
@@ -528,7 +578,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
@@ -562,7 +612,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -572,7 +622,7 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -661,7 +711,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -672,4 +722,4 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Change ^[[0;2m?^[[0m Help
+40
View File
@@ -0,0 +1,40 @@
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A/Enter Choose B/Esc Back ? Help
+12
View File
@@ -0,0 +1,12 @@
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back ? Help
+15
View File
@@ -0,0 +1,15 @@
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back ? Help
+24
View File
@@ -0,0 +1,24 @@
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A/Enter Choose B/Esc Back ? Help
+40
View File
@@ -0,0 +1,40 @@
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A/Enter Tick B/Esc Done ? Help
+12
View File
@@ -0,0 +1,12 @@
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done ? Help
+15
View File
@@ -0,0 +1,15 @@
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done ? Help
+24
View File
@@ -0,0 +1,24 @@
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A/Enter Tick B/Esc Done ? Help
+1 -1
View File
@@ -2,7 +2,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
+1 -1
View File
@@ -2,7 +2,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
+1 -1
View File
@@ -2,7 +2,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
+1 -1
View File
@@ -2,7 +2,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
Y, o, Tab Change
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
+2 -2
View File
@@ -7,7 +7,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -37,4 +37,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+2 -2
View File
@@ -7,6 +7,6 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -8,8 +8,8 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -7,7 +7,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -21,4 +21,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+2 -2
View File
@@ -11,7 +11,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -37,4 +37,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+1 -1
View File
@@ -9,4 +9,4 @@
Only what starts: no
Show the games
1-4 of 9
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -10,6 +10,6 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -11,7 +11,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -21,4 +21,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+2 -2
View File
@@ -5,7 +5,7 @@
> Close
Details
Options
Change
@@ -37,4 +37,4 @@
A/Enter Close B/Esc Back Y/o Options ? Help
A/Enter Close B/Esc Back Y/o Change ? Help
+2 -2
View File
@@ -6,7 +6,7 @@
> Close
Details
Options
Change
A Close B Back Y Options ? Help
A Close B Back Y Change ? Help
+2 -2
View File
@@ -6,10 +6,10 @@
> Close
Details
Options
Change
A Close B Back Y Options ? Help
A Close B Back Y Change ? Help
+2 -2
View File
@@ -5,7 +5,7 @@
> Close
Details
Options
Change
@@ -21,4 +21,4 @@
A/Enter Close B/Esc Back Y/o Options ? Help
A/Enter Close B/Esc Back Y/o Change ? Help
+2 -2
View File
@@ -10,7 +10,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -37,4 +37,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+1 -1
View File
@@ -9,4 +9,4 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -10,6 +10,6 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
A Install B Back Y Options ? Help
A Install B Back Y Change ? Help
+2 -2
View File
@@ -10,7 +10,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -21,4 +21,4 @@
A/Enter Install B/Esc Back Y/o Options ? Help
A/Enter Install B/Esc Back Y/o Change ? Help
+164 -56
View File
@@ -411,9 +411,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 40x15
RetroBIOS: RetroArch
@@ -425,11 +425,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 80x24
RetroBIOS: RetroArch
@@ -440,7 +440,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -454,7 +454,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -464,10 +464,10 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -477,13 +477,13 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 80x24
RetroBIOS: RetroArch
@@ -492,7 +492,7 @@
> Close
Details
Options
Change
@@ -508,7 +508,7 @@
A Close B Back Y Options
A Close B Back Y Change
=== systems 40x12
RetroBIOS: Choose systems
@@ -563,60 +563,168 @@
2 of 3 systems: 4 files, 1.0 MB
A Tick B Done
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
A Open B Back <> Set
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
A Open B Back <> Set
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
A Open B Back Left/Right Set
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== regions 40x12
RetroBIOS: Preferred regions
@@ -976,7 +1084,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -989,7 +1097,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1005,7 +1113,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1037,7 +1145,7 @@
Only what starts: no
Show the games
1-4 of 9
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1051,9 +1159,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 80x24
RetroBIOS: RetroArch
@@ -1068,7 +1176,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1078,7 +1186,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== games 80x24
RetroBIOS: Games on this card
@@ -1195,7 +1303,7 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 40x15
RetroBIOS: RetroArch
@@ -1209,9 +1317,9 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 80x24
RetroBIOS: RetroArch
@@ -1225,7 +1333,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1236,4 +1344,4 @@
A Install B Back Y Options
A Install B Back Y Change
+164 -56
View File
@@ -411,9 +411,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 40x15
RetroBIOS: RetroArch
@@ -425,11 +425,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 80x24
RetroBIOS: RetroArch
@@ -440,7 +440,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -454,7 +454,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -464,10 +464,10 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -477,13 +477,13 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 80x24
RetroBIOS: RetroArch
@@ -492,7 +492,7 @@
> Close
Details
Options
Change
@@ -508,7 +508,7 @@
A Close B Back Y Options
A Close B Back Y Change
=== systems 40x12
RetroBIOS: Choose systems
@@ -563,60 +563,168 @@
2 of 3 systems: 4 files, 1.0 MB
A Tick B Done
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
A Open B Back <> Set
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
A Open B Back <> Set
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
A Open B Back Left/Right Set
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== regions 40x12
RetroBIOS: Preferred regions
@@ -976,7 +1084,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -989,7 +1097,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1005,7 +1113,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1037,7 +1145,7 @@
Only what starts: no
Show the games
1-4 of 9
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1051,9 +1159,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 80x24
RetroBIOS: RetroArch
@@ -1068,7 +1176,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1078,7 +1186,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== games 80x24
RetroBIOS: Games on this card
@@ -1195,7 +1303,7 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 40x15
RetroBIOS: RetroArch
@@ -1209,9 +1317,9 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 80x24
RetroBIOS: RetroArch
@@ -1225,7 +1333,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1236,4 +1344,4 @@
A Install B Back Y Options
A Install B Back Y Change
+164 -56
View File
@@ -411,9 +411,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 40x15
RetroBIOS: RetroArch
@@ -425,11 +425,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan 80x24
RetroBIOS: RetroArch
@@ -440,7 +440,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -454,7 +454,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -464,10 +464,10 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -477,13 +477,13 @@
> Close
Details
Options
Change
A Close B Back Y Options
A Close B Back Y Change
=== plan-in-place 80x24
RetroBIOS: RetroArch
@@ -492,7 +492,7 @@
> Close
Details
Options
Change
@@ -508,7 +508,7 @@
A Close B Back Y Options
A Close B Back Y Change
=== systems 40x12
RetroBIOS: Choose systems
@@ -563,60 +563,168 @@
2 of 3 systems: 4 files, 1.0 MB
A Tick B Done
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
A Open B Back <> Set
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
A Open B Back <> Set
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
A Open B Back Left/Right Set
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose B Back
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick B Done
=== regions 40x12
RetroBIOS: Preferred regions
@@ -976,7 +1084,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -989,7 +1097,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1005,7 +1113,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
Y, Tab, o Change
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1037,7 +1145,7 @@
Only what starts: no
Show the games
1-4 of 9
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1051,9 +1159,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-games 80x24
RetroBIOS: RetroArch
@@ -1068,7 +1176,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1078,7 +1186,7 @@
A Install B Back Y Options
A Install B Back Y Change
=== games 80x24
RetroBIOS: Games on this card
@@ -1195,7 +1303,7 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 40x15
RetroBIOS: RetroArch
@@ -1209,9 +1317,9 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
A Install B Back Y Options
A Install B Back Y Change
=== plan-record 80x24
RetroBIOS: RetroArch
@@ -1225,7 +1333,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1236,4 +1344,4 @@
A Install B Back Y Options
A Install B Back Y Change
+164 -56
View File
@@ -386,9 +386,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan 40x15
RetroBIOS: RetroArch
@@ -400,11 +400,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan 80x24
RetroBIOS: RetroArch
@@ -415,7 +415,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -429,7 +429,7 @@
Enter Install Esc Back o Options ? Help
Enter Install Esc Back o Change ? Help
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -439,10 +439,10 @@
> Close
Details
Options
Change
Enter Close Esc Back o Options
Enter Close Esc Back o Change
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -452,13 +452,13 @@
> Close
Details
Options
Change
Enter Close Esc Back o Options
Enter Close Esc Back o Change
=== plan-in-place 80x24
RetroBIOS: RetroArch
@@ -467,7 +467,7 @@
> Close
Details
Options
Change
@@ -483,7 +483,7 @@
Enter Close Esc Back o Options ? Help
Enter Close Esc Back o Change ? Help
=== systems 40x12
RetroBIOS: Choose systems
@@ -538,60 +538,168 @@
2 of 3 systems: 4 files, 1.0 MB
Enter Tick Esc Done ? Help
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
Enter Open Esc Back <> Set ? Help
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
Enter Open Esc Back <> Set ? Help
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
Enter Open Esc Back Left/Right Set ? Help
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Enter Choose Esc Back ? Help
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Enter Choose Esc Back ? Help
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Enter Choose Esc Back ? Help
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Enter Tick Esc Done ? Help
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Enter Tick Esc Done ? Help
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (/ to type)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Enter Tick Esc Done ? Help
=== regions 40x12
RetroBIOS: Preferred regions
@@ -1083,7 +1191,7 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
o, Tab Change
d Details
Esc, Backspace Back
q, Ctrl-C Quit
@@ -1096,7 +1204,7 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
o, Tab Change
d Details
Esc, Backspace Back
q, Ctrl-C Quit
@@ -1112,7 +1220,7 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
o, Tab Change
d Details
Esc, Backspace Back
q, Ctrl-C Quit
@@ -1144,7 +1252,7 @@
Only what starts: no
Show the games
1-4 of 9
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1158,9 +1266,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan-games 80x24
RetroBIOS: RetroArch
@@ -1175,7 +1283,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1185,7 +1293,7 @@
Enter Install Esc Back o Options ? Help
Enter Install Esc Back o Change ? Help
=== games 40x12
RetroBIOS: Games on this card
@@ -1360,7 +1468,7 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan-record 40x15
RetroBIOS: RetroArch
@@ -1374,9 +1482,9 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
Enter Install Esc Back o Options
Enter Install Esc Back o Change
=== plan-record 80x24
RetroBIOS: RetroArch
@@ -1390,7 +1498,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1401,4 +1509,4 @@
Enter Install Esc Back o Options ? Help
Enter Install Esc Back o Change ? Help
+164 -56
View File
@@ -440,9 +440,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan 40x15
RetroBIOS: RetroArch
@@ -454,11 +454,11 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan 80x24
RetroBIOS: RetroArch
@@ -469,7 +469,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -483,7 +483,7 @@
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -493,10 +493,10 @@
> Close
Details
Options
Change
A Close R2 Back L2 Options
A Close R2 Back L2 Change
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -506,13 +506,13 @@
> Close
Details
Options
Change
A Close R2 Back L2 Options
A Close R2 Back L2 Change
=== plan-in-place 80x24
RetroBIOS: RetroArch
@@ -521,7 +521,7 @@
> Close
Details
Options
Change
@@ -537,7 +537,7 @@
A Close R2 Back L2 Options
A Close R2 Back L2 Change
=== systems 40x12
RetroBIOS: Choose systems
@@ -592,60 +592,168 @@
2 of 3 systems: 4 files, 1.0 MB
A Tick R2 Done
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
A Open R2 Back <> Set
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
A Open R2 Back <> Set
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
A Open R2 Back Left/Right Set
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose R2 Back
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose R2 Back
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
A Choose R2 Back
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick R2 Done
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick R2 Done
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (with a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
A Tick R2 Done
=== regions 40x12
RetroBIOS: Preferred regions
@@ -1079,7 +1187,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
L2, Tab, o Change
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1092,7 +1200,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
L2, Tab, o Change
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1108,7 +1216,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
L2, Tab, o Change
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1140,7 +1248,7 @@
Only what starts: no
Show the games
1-4 of 9
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1154,9 +1262,9 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan-games 80x24
RetroBIOS: RetroArch
@@ -1171,7 +1279,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1181,7 +1289,7 @@
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== games 80x24
RetroBIOS: Games on this card
@@ -1298,7 +1406,7 @@
Choose systems
Copy from an old card or a folder
1-4 of 8
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan-record 40x15
RetroBIOS: RetroArch
@@ -1312,9 +1420,9 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
A Install R2 Back L2 Options
A Install R2 Back L2 Change
=== plan-record 80x24
RetroBIOS: RetroArch
@@ -1328,7 +1436,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
@@ -1339,4 +1447,4 @@
A Install R2 Back L2 Options
A Install R2 Back L2 Change
+152 -44
View File
@@ -440,7 +440,7 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
Start Install B Back
=== plan 40x15
@@ -454,7 +454,7 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
@@ -469,7 +469,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -493,7 +493,7 @@
> Close
Details
Options
Change
Start Close B Back
@@ -506,7 +506,7 @@
> Close
Details
Options
Change
@@ -521,7 +521,7 @@
> Close
Details
Options
Change
@@ -592,60 +592,168 @@
2 of 3 systems: 4 files, 1.0 MB
Start Tick B Done
=== options 40x12
RetroBIOS: Options
=== change 40x12
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
1-8 of 18
Start Open B Back <> Set
=== options 40x15
RetroBIOS: Options
=== change 40x15
RetroBIOS: Change
What to install
> Preferred regions: North America, Ja
Game data: kept
Installed cores only: no (1 found)
Cores: all
Parallel downloads: 8
Emulators: all
Game data: kept
Where
BIOS folder: ~/.config...ch/system
Copy from: none
Preview the file list
Show the command line
Sets --region
From a pack: none
For which device
Device: every board
1-11 of 18
Start Open B Back <> Set
=== options 80x24
RetroBIOS: Options
Each row is an option of the command line, named on the right.
=== change 80x24
RetroBIOS: Change
What to install
> Preferred regions: North America, Japan --region
Game data: kept --no-game-data
Installed cores only: no (1 found) --installed-cores
Cores: all --core
Parallel downloads: 8 --jobs
Emulators: all --emulator
Game data: kept --no-game-data
Where
BIOS folder: ~/.config/retroarch/system --dest
Copy from: none --from
From a pack: none --from-pack
For which device
Device: every board --target
Installed cores only: no (1 found) --installed-cores
How
Without the internet: no --offline
Parallel downloads: 8 --jobs
See
Preview the file list --dry-run
Show the command line
Start Open B Back Left/Right Set
=== device 40x12
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Start Choose B Back
=== device 40x15
RetroBIOS: Device
Choose the board, the chip of the
device the games run on. Every board
fits any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Start Choose B Back
=== device 80x24
RetroBIOS: Device
Choose the board, the chip of the device the games run on. Every board fits
any device.
> (x) h700 named by the card
( ) bcm2711 rpi4
( ) x86_64
( ) Every board
Start Choose B Back
=== emulators 40x12
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (Select shows a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Start Tick B Done
=== emulators 40x15
RetroBIOS: Emulators
Tick the emulators to install for.
With none ticked, every emulator's
files are installed.
Filter (Select shows a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Start Tick B Done
=== emulators 80x24
RetroBIOS: Emulators
Tick the emulators to install for. With none ticked, every emulator's files
are installed.
Filter (Select shows a keyboard)
[ ] mesen
> [x] pcsx_rearmed
None
Done
Start Tick B Done
=== regions 40x12
RetroBIOS: Preferred regions
@@ -1137,7 +1245,7 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
o, Tab Change
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1150,7 +1258,7 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
o, Tab Change
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1166,7 +1274,7 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
o, Tab Change
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
@@ -1212,7 +1320,7 @@
Choose systems
Copy from an old card or a folder
Details
Options
Change
Quit
Start Install B Back
=== plan-games 80x24
@@ -1229,7 +1337,7 @@
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Change
Quit
@@ -1428,7 +1536,7 @@
Copy from an old card or a folder
Change where
Details
Options
Change
Quit
Start Install B Back
=== plan-record 80x24
@@ -1444,7 +1552,7 @@
Copy the BIOS files from an old card or a folder
Change where
Details
Options
Change
Quit
+6 -2
View File
@@ -66,7 +66,11 @@ JOURNEY_WORDS = {
"update": 70,
"one_system": 179,
"one_system_again": 67,
"what_is_missing": 207,
# Change holds every option one level down now (design 4.4): its
# headings and the rows for Emulators, a pack, the device and the
# internet, the intro sentence dropped, 10 words on each of its two
# frames.
"what_is_missing": 227,
# The plan of the setup found comes first now (33 words), the setups
# one Esc away, and the last plan names Change where (2 words).
"another_device": 265,
@@ -319,7 +323,7 @@ class Journeys(unittest.TestCase):
term = self.start(repo)
term.wait("files to download", timeout=40)
self.press(term, "o")
term.wait("Each row is an option")
term.wait("RetroBIOS: Change")
self.press(term, END, UP)
term.wait("> Preview the file list")
self.press(term, "\r")
+512 -24
View File
@@ -450,6 +450,12 @@ class HoldingPack:
return (None, entry)
def option_focus(state: install.TuiState, action: str) -> None:
"""The focus on the Change row doing action: its rows sit under
headings, which no index of the flat list kept."""
state.focus["options"] = [row.action for row in install.tui_rows(state)].index(action)
def press(state: install.TuiState, *pressed) -> list:
effects = []
for key in pressed:
@@ -495,6 +501,7 @@ class Flow(unittest.TestCase):
state = checked_state()
state.passthrough = started.passthrough
state.from_folders = started.from_folders
state.packs = started.packs
for run in ("check", "install"):
argv = install.tui_argv(state, run, "py", "i.py")
for folder in ("old-card", "backup.zip"):
@@ -556,9 +563,12 @@ class Flow(unittest.TestCase):
press(state, "o")
self.assertEqual(state.screen, "options")
rows = install.tui_rows(state)
self.assertEqual([row.right for row in rows], [
"--region", "--no-game-data", "--installed-cores", "--core", "--jobs", "--dest",
"--from", "--dry-run", ""])
# Grouped by what each decides, a heading above each group.
self.assertEqual([row.right or row.label for row in rows], [
"What to install", "--region", "--core", "--emulator", "--no-game-data",
"Where", "--dest", "--from", "--from-pack",
"For which device", "--target", "--installed-cores",
"How", "--offline", "--jobs", "See", "--dry-run", "Show the command line"])
press(state, "enter")
self.assertEqual(state.screen, "regions")
# Ticked in the order of preference, then moved up.
@@ -574,7 +584,10 @@ class Flow(unittest.TestCase):
["[2] Japan", "[1] North America", "None", "Done"])
press(state, "shift-down")
self.assertEqual(state.regions, ["japan", "north-america"])
press(state, "esc", "down", "enter", "down", "right", "down", "down", "right", "right")
# Down passes the headings: Game data, Installed cores only, then
# Parallel downloads.
press(state, "esc", "down", "down", "down", "enter", *["down"] * 5, "right",
"down", "down", "right", "right")
self.assertTrue(state.no_game_data)
self.assertTrue(state.installed_only)
self.assertEqual(state.jobs, 10)
@@ -586,7 +599,7 @@ class Flow(unittest.TestCase):
def test_cores_checklist(self):
state = checked_state()
press(state, "o")
state.focus["options"] = 3
option_focus(state, "cores")
press(state, "enter")
self.assertEqual(state.screen, "cores")
self.assertEqual([row.value for row in install.tui_rows(state)
@@ -610,7 +623,7 @@ class Flow(unittest.TestCase):
def test_preview_is_a_dry_run(self):
state = checked_state()
press(state, "o")
state.focus["options"] = 7
option_focus(state, "preview")
self.assertEqual(press(state, "enter"), [("run", "preview")])
self.assertEqual(install.tui_argv(state, "preview", "py", "i.py")[-2:],
["--dry-run", "--events"])
@@ -805,7 +818,7 @@ class Flow(unittest.TestCase):
def test_events_of_an_abandoned_run_are_ignored(self):
state = checked_state()
press(state, "o")
state.focus["options"] = 7
option_focus(state, "preview")
press(state, "enter")
old = state.run_id
self.assertEqual(press(state, "esc"), [("kill",)])
@@ -983,8 +996,15 @@ def golden_states() -> dict:
states["systems"] = systems
options = checked_state()
options.stack.append("options")
options.focus["options"] = 1
options.regions = ["north-america", "japan"]
states["options"] = options
states["change"] = options
states["device"] = device_state()
emulators = checked_state()
emulators.stack += ["options", "emulators"]
emulators.emulators = ["pcsx_rearmed"]
emulators.focus["emulators"] = 2
states["emulators"] = emulators
regions = checked_state()
regions.stack += ["options", "regions"]
regions.regions = ["north-america"]
@@ -1046,6 +1066,30 @@ def golden_states() -> dict:
return states
# A board list as install/targets/ publishes it, read by Device: the boards
# by the names the list gives them, the device images each one runs.
TARGETS = {"bcm2711": {"cores": ["pcsx_rearmed"], "images": ["rpi4"]},
"h700": {"cores": ["pcsx_rearmed", "mesen"],
"images": ["anbernic-rg35xx-plus", "anbernic-rg40xx-h"]},
"x86_64": {"cores": None}}
def device_state(board: str = "h700") -> install.TuiState:
"""Device opened from Change, the board list in, the card in the reader
naming its board (the check's board event)."""
state = checked_state()
if board:
state.board_seen = ("retroarch", state.dest, board, True, False)
state.stack.append("options")
install.tui_update(state, Key("home"))
rows = install.tui_rows(state)
state.focus["options"] = [row.action for row in rows].index("device")
effects = install.tui_update(state, Key("enter"))
assert effects == [("targets", "retroarch")], effects
install.tui_receive(state, ("targets", "retroarch", TARGETS, ""))
return state
def record_setup(choice: list[str] | None = None) -> dict:
"""A record kept on 3 November of this year: the plan says 3 Nov in
any year it runs."""
@@ -1465,12 +1509,12 @@ class PadRoutes(unittest.TestCase):
def test_the_plan_bar_of_each_route(self):
expected = {
"both": "A/Enter Install B/Esc Back Y/o Options ? Help",
"keys": "Enter Install Esc Back o Options ? Help",
"gptokeyb": "A Install B Back Y Options",
"evmapy": "A Install B Back Y Options",
"both": "A/Enter Install B/Esc Back Y/o Change ? Help",
"keys": "Enter Install Esc Back o Change ? Help",
"gptokeyb": "A Install B Back Y Change",
"evmapy": "A Install B Back Y Change",
"muxterm": "Start Install B Back",
"miyoo": "A Install R2 Back L2 Options",
"miyoo": "A Install R2 Back L2 Change",
}
for route, bar in expected.items():
with self.subTest(route=route):
@@ -2003,7 +2047,7 @@ class TicksBarAndPaths(unittest.TestCase):
ticked = set(state.ticked)
press(state, "esc", "o")
self.assertEqual(state.screen, "options")
state.focus["options"] = 1
option_focus(state, "game_data")
press(state, "enter")
self.assertTrue(state.no_game_data)
effects = press(state, "esc")
@@ -3257,12 +3301,12 @@ class SaveDirectoryLeftOut(unittest.TestCase):
plan = " ".join(" ".join(install.tui_view(state, 120, 40)).split())
# The plan names the row that sets it, the result the option a
# command carries.
self.assertIn(line + "Choose it in Options, Save folder (--save-dir). Its place is "
self.assertIn(line + "Choose it in Change, Save folder (--save-dir). Its place is "
"not known.", plan)
state.stack.append("result")
state.code = 0
state.summary = {**summary, "mode": "install", "installed": 5}
self.assertIn(line + "Choose it in Options, Save folder (--save-dir), next time.",
self.assertIn(line + "Choose it in Change, Save folder (--save-dir), next time.",
install.tui_outcome(state)[1])
@@ -4128,7 +4172,7 @@ class BackTicksAndSaveFolder(unittest.TestCase):
state.manifest = {**state.manifest, "save_directory": {"folder": "saves",
"by_core": True}}
lines = install._unplaced_lines(summary, state)
self.assertIn("Options, Save folder (--save-dir)", lines[0])
self.assertIn("Change, Save folder (--save-dir)", lines[0])
def test_a_size_keeps_its_unit(self):
for width in range(20, 45):
@@ -5095,7 +5139,7 @@ class EndToEnd(unittest.TestCase):
term = self.start("--platform", "knulli", "--dest", str(root))
term.wait("files to download")
term.send("o")
term.wait("Each row is an option")
term.wait("RetroBIOS: Change")
for _step in range(20):
if "> Put RetroBIOS on this card: no" in term.settle():
break
@@ -5231,13 +5275,17 @@ class EndToEnd(unittest.TestCase):
term = self.start("--platform", "retroarch", "--dest", str(repo.dest))
term.wait("6 files to download")
term.send("o")
screen = term.wait("Each row is an option")
screen = term.wait("RetroBIOS: Change")
self.assertIn("--no-game-data", screen)
term.send("\r")
term.wait("Preferred regions")
term.send(DOWN, "\r", "\x1b")
screen = term.wait("Preferred regions: North America")
term.send(DOWN, RIGHT, "\x1b")
for _step in range(8):
if "> Game data: kept" in term.settle():
break
term.send(DOWN)
term.send(RIGHT, "\x1b")
# Back on the plan, the check runs again under the new options.
screen = term.wait("4 files to download")
self.assertIn("> Install", screen)
@@ -10688,7 +10736,7 @@ class MouseEnabled(unittest.TestCase):
self.assertFalse(install.tui_wants_mouse(state, drawn(state, 80, 24)))
# The result takes a tap on its Exit: its text is printed again in
# the terminal once it closes, selected there as anywhere.
for name in ("setup", "platforms", "plan", "systems", "options", "error", "quit",
for name in ("setup", "platforms", "plan", "systems", "change", "error", "quit",
"result"):
with self.subTest(screen=name):
state = states[name]
@@ -10749,6 +10797,13 @@ class MouseOnEveryScreen(unittest.TestCase):
self.assertEqual(lines[line].style == "focus", index == focus)
# The whole width, the text's end or not.
effects = tap(state, cols - 1, line)
if row_list[index].action == "heading":
# A heading names the rows under it: no
# choice, nothing happens.
self.assertEqual(effects, [])
self.assertEqual((state.stack, state.focus),
(base.stack, base.focus))
continue
if row_list[index].action in install.TUI_TICK_ROWS:
# A tick is ticked as Space ticks it, focus
# moved there first.
@@ -13357,7 +13412,7 @@ class TheSettleRunsFromTheFrameShown(unittest.TestCase):
term.wait("> Install")
term.settle()
term.send("o")
term.wait("RetroBIOS: Options")
term.wait("RetroBIOS: Change")
term.settle()
time.sleep(1.0)
col, line = self.bar_entry(term, "Back")
@@ -15119,7 +15174,7 @@ SCREEN_WORDS = {
"folder-card": (52, 52, 50, 50), "browse": (17, 17, 15, 15), "path": (23, 23, 25, 25),
"create": (23, 23, 21, 21), "checking": (18, 18, 17, 17), "plan": (31, 31, 31, 31),
"plan-in-place": (22, 22, 19, 19), "systems": (36, 37, 36, 36),
"options": (40, 42, 59, 59), "regions": (45, 44, 42, 42), "cores": (47, 47, 45, 45),
"regions": (45, 44, 42, 42), "cores": (47, 47, 45, 45),
"preview": (29, 29, 28, 28), "command": (22, 22, 16, 16), "confirm": (22, 22, 20, 20),
"installing": (32, 32, 31, 31), "result": (33, 33, 31, 31), "error": (37, 34, 32, 31),
"quit": (14, 14, 12, 12), "help": (24, 26, 26, 26), "plan-games": (36, 46, 54, 54),
@@ -15129,6 +15184,13 @@ SCREEN_WORDS = {
# press back to the whole list) and Change where (back to the setups,
# the plan having opened on the one found).
"plan-record": (38, 42, 42, 42),
# Change holds every option one level below the plan (design 4.4): the
# rows for Emulators, a pack, the device and the internet, and the five
# headings that group them, the intro sentence they replace dropped.
"change": (32, 42, 72, 72),
# A list of boards and one of emulators, each with the line that says
# what the choice does and the gloss of "board".
"device": (35, 35, 33, 33), "emulators": (29, 29, 27, 27),
}
@@ -15313,7 +15375,7 @@ class WhatToActOnStaysOnTheScreen(unittest.TestCase):
state = checked_state()
state.manifest = {**MANIFEST, "save_directory": {"folder": "saves", "by_core": True}}
state.check_summary = {"skipped": [{"reason": "no_save_directory", "files": 2}]}
self.assertIn("Choose it in Options, Save folder (--save-dir).", self.text(state))
self.assertIn("Choose it in Change, Save folder (--save-dir).", self.text(state))
def test_files_that_could_not_be_read_are_counted_where_no_row_says_so(self):
unread = [{"event": "unreadable", "platform": "retroarch", "folder": "/media/OLD",
@@ -15340,5 +15402,431 @@ class WhatToActOnStaysOnTheScreen(unittest.TestCase):
self.assertNotIn("Read the first", text)
class DeviceAndEmulatorScreens(unittest.TestCase):
"""Device chooses --target and --every-board, Emulators --emulator, and
Change keeps every option one level below the plan, grouped by intent."""
def setUp(self):
patcher = mock.patch.object(install, "_mounted_cards", return_value=[])
patcher.start()
self.addCleanup(patcher.stop)
def text(self, state: install.TuiState, cols: int = 80, rows: int = 24) -> str:
return "\n".join(str(line) for line in install.tui_view(state, cols, rows))
def focus(self, state: install.TuiState, action: str, value: object = None) -> None:
rows = install.tui_rows(state)
state.focus[state.screen] = next(
index for index, row in enumerate(rows)
if row.action == action and (value is None or row.value == value))
def test_change_groups_every_option_under_headings_focus_skips(self):
state = checked_state()
press(state, "o")
rows = install.tui_rows(state)
headings = [row.label for row in rows if row.action == "heading"]
self.assertEqual(headings, list(install.TUI_CHANGE_GROUPS))
self.assertNotEqual(rows[state.focus["options"]].action, "heading")
flags = {row.right for row in rows if row.action != "heading"}
for flag in ("--region", "--core", "--emulator", "--no-game-data", "--dest", "--from",
"--from-pack", "--target", "--installed-cores", "--jobs", "--offline",
"--dry-run"):
self.assertIn(flag, flags)
# Down and Up never stop on a heading, Home neither.
for key in ("down",) * len(rows) + ("up",) * len(rows) + ("home", "end", "home"):
press(state, key)
self.assertNotEqual(install.tui_rows(state)[state.focus["options"]].action,
"heading", key)
# Up on the first row stays: the list does not wrap past its heading.
press(state, "home", "up")
self.assertEqual(state.focus["options"], 1)
# The plan's row and bar name the screen.
plan = checked_state()
self.assertIn("Change", [row.label for row in install.tui_rows(plan)])
self.assertIn("Y/o Change", self.text(plan))
def test_a_tap_on_a_heading_does_nothing(self):
state = checked_state()
press(state, "o")
before = dict(state.focus)
rows = install.tui_rows(state)
index = next(i for i, row in enumerate(rows) if row.action == "heading")
state.cols, state.rows = 80, 24
state.hits = install.tui_hits(state, install.tui_view(state, 80, 24))
number = next(target[0] for target in state.hits.targets
if target[3][:2] == ("row", index))
state.now = state.hits.shown + 1
install.tui_mouse(state, install.TuiMouse(0, 3, number + 1, False))
self.assertEqual(install.tui_mouse(state, install.TuiMouse(0, 3, number + 1, True)), [])
self.assertEqual(state.focus, before)
def test_device_lists_the_card_board_first_and_chosen(self):
state = device_state()
self.assertEqual(state.screen, "device")
rows = install.tui_rows(state)
self.assertEqual([row.label for row in rows],
["(x) h700", "( ) bcm2711", "( ) x86_64", "( ) Every board"])
self.assertEqual(rows[0].right, "named by the card")
self.assertEqual(rows[1].right, "rpi4")
self.assertEqual(state.focus["device"], 0)
# Chosen as it is: nothing to say on the command line.
press(state, "enter")
self.assertEqual(state.screen, "options")
self.assertEqual([flag for flag in install.tui_flags(state)
if flag[0] in ("--target", "--every-board")], [])
self.assertIn("Device: h700, named by the card", self.text(state))
def test_on_the_device_itself_it_says_this_device(self):
state = checked_state()
state.board_seen = ("retroarch", state.dest, "bcm2711", True, True)
state.stack.append("options")
self.assertIn("Device: bcm2711, this device", self.text(state))
def test_the_board_event_is_kept_across_checks(self):
state = checked_state()
state.run, state.running = "check", True
install.tui_receive(state, ("event", state.run_id, {
"event": "board", "platform": "retroarch", "board": "h700", "applied": True,
"message": "Board h700 found on the card (--every-board installs all boards)"}))
with mock.patch.object(install, "detect_board", return_value=None):
self.assertEqual(install._board_seen(state)[:2], ("h700", True))
install._start_run(state, "check")
self.assertEqual(install._board_seen(state)[:2], ("h700", True))
def test_another_board_and_every_board_set_their_flag(self):
state = device_state()
self.focus(state, "board", "bcm2711")
press(state, "enter")
self.assertIn(("--target", "bcm2711"), install.tui_flags(state))
self.assertIn("--target=bcm2711", install.tui_argv(state, "install", "py", "i.py"))
self.assertIn("Device: bcm2711", self.text(state))
# Back on the plan, counted again for the board.
self.assertEqual(press(state, "esc"), [("run", "check")])
state = device_state()
self.focus(state, "board", "")
press(state, "enter")
self.assertEqual([flag for flag in install.tui_flags(state)
if flag[0] in ("--target", "--every-board")],
[("--every-board", None)])
self.assertIn("Device: every board", self.text(state))
def test_with_no_board_read_every_board_is_the_choice_and_no_flag(self):
state = device_state(board="")
self.assertEqual(install.tui_rows(state)[-1].label, "(x) Every board")
self.assertEqual(state.focus["device"], 3)
press(state, "enter")
self.assertEqual([flag for flag in install.tui_flags(state)
if flag[0] in ("--target", "--every-board")], [])
def test_a_board_list_that_cannot_be_read_is_said(self):
state = checked_state()
state.stack.append("options")
self.focus(state, "device")
press(state, "enter")
self.assertIn("Reading the board list...", self.text(state))
install.tui_receive(state, ("targets", "retroarch", None,
"The board list could not be read."))
self.assertIn("The board list could not be read.", self.text(state))
self.assertEqual(press(state, "esc"), [])
self.assertEqual(state.screen, "options")
def test_the_command_line_choice_is_the_one_shown(self):
args = _args(platform="retroarch", dest=SYSTEM_DIR, target="bcm2711",
emulator=["mesen"])
state, _effects = install.tui_start(args, "linux", detect=False)
self.assertEqual((state.target, state.emulators), ("bcm2711", ["mesen"]))
self.assertNotIn("--target", [flag for flag, _value in state.passthrough])
flags = install.tui_flags(state)
self.assertIn(("--target", "bcm2711"), flags)
self.assertIn(("--emulator", "mesen"), flags)
def test_emulators_ticked_are_the_emulator_flags(self):
state = checked_state()
state.stack.append("options")
self.focus(state, "emulators")
press(state, "enter")
self.assertEqual(state.screen, "emulators")
rows = install.tui_rows(state)
self.assertEqual([row.label for row in rows if row.action == "emulator"],
["[ ] mesen", "[ ] pcsx_rearmed"])
self.assertEqual(rows[state.focus["emulators"]].value, "mesen")
press(state, " ")
self.assertEqual(state.emulators, ["mesen"])
self.assertIn(("--emulator", "mesen"), install.tui_flags(state))
press(state, "n")
self.assertEqual(state.emulators, [])
press(state, " ", "esc")
self.assertEqual(state.screen, "options")
self.assertIn("Emulators: mesen", self.text(state))
def test_without_the_internet_sets_offline_for_the_runs(self):
state = checked_state()
state.stack.append("options")
self.focus(state, "offline")
with mock.patch.dict(os.environ, {}, clear=False):
os.environ.pop(install.OFFLINE_VARIABLE, None)
self.assertIn("Without the internet: no", self.text(state))
self.assertEqual(press(state, "enter"), [("offline", True)])
install.set_offline(True)
self.assertIn("Without the internet: yes", self.text(state))
self.assertIn(("--offline", None), install.tui_flags(state))
self.assertEqual(press(state, "left"), [("offline", False)])
install.set_offline(False)
self.assertNotIn(("--offline", None), install.tui_flags(state))
def test_from_a_pack_opens_the_browser_on_zips_and_reads_the_pack(self):
root = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
self.addCleanup(shutil.rmtree, root, True)
(root / "Downloads").mkdir()
pack = root / "Downloads" / "RetroArch_BIOS_Pack.zip"
pack.write_bytes(b"PK")
(root / "Downloads" / "notes.txt").write_text("x")
state = checked_state()
state.home = root
state.stack.append("options")
self.focus(state, "pack")
press(state, "enter")
self.assertEqual((state.screen, state.browse_for), ("browse", "pack"))
rows = install.tui_rows(state)
self.assertNotIn("use", [row.action for row in rows])
self.assertEqual([row.label for row in rows if row.action == "zip"],
["RetroArch_BIOS_Pack.zip"])
self.focus(state, "zip")
self.assertIn("A/Enter Use this pack", self.text(state))
self.assertEqual(press(state, "enter"), [("pack", pack)])
# Refused: said, the browser stays.
install.tui_receive(state, ("pack_opened", pack, "Not a pack."))
self.assertEqual(state.screen, "browse")
self.assertIn("Not a pack.", self.text(state))
effects = install.tui_receive(state, ("pack_opened", pack, ""))
self.assertEqual(effects, [("fetch", "retroarch")])
self.assertEqual(state.packs, [pack])
self.assertIn(("--from-pack", str(pack)), install.tui_flags(state))
def test_open_tui_pack_refuses_another_platforms_pack(self):
root = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
self.addCleanup(shutil.rmtree, root, True)
pack = root / "Batocera_BIOS_Pack.zip"
with zipfile.ZipFile(pack, "w") as archive:
archive.writestr("manifest.json", json.dumps({"platform": "batocera",
"files": []}))
previous = install.LOCAL.pack
self.addCleanup(setattr, install.LOCAL, "pack", previous)
problem = install.open_tui_pack(pack, "retroarch")
self.assertIs(install.LOCAL.pack, previous)
self.assertTrue(problem)
def _parity_list(root: Path) -> tuple[Path, Path]:
"""A RetroArch list whose cores per board pick other files, a shared
destination two cores want different bytes at, and the copies of every
file in a folder: an install from it needs no network."""
payloads = root / "copies"
payloads.mkdir()
entries = []
alternative = {}
for name, cores, systems in (("plat.bin", None, ["sony-playstation"]),
("pcsx/extra.bin", ["pcsx_rearmed"], ["sony-playstation"]),
("mesen/nes.bin", ["mesen"], ["nintendo-nes"]),
("nes_plat.bin", None, ["nintendo-nes"]),
("shared.bin", ["pcsx_rearmed"], ["sony-playstation"]),
("shared.bin#mesen", ["mesen"], ["nintendo-nes"])):
payload = name.encode() * 8
stored = name.replace("/", "_").replace("#", "_")
(payloads / stored).write_bytes(payload)
entry = {"dest": name.split("#")[0], "size": len(payload),
"sha1": hashlib.sha1(payload).hexdigest(),
"sha256": hashlib.sha256(payload).hexdigest(),
"repo_path": f"bios/{stored}", "cores": cores, "systems": systems}
if "#" in name:
alternative = {field: entry[field] for field in
("sha1", "sha256", "size", "repo_path", "cores")}
continue
entries.append(entry)
next(entry for entry in entries if entry["dest"] == "shared.bin")["alternatives"] = [
alternative]
listed = root / "list"
(listed / "targets").mkdir(parents=True)
manifest = {"manifest_version": 2, "platform": "retroarch", "files": entries,
"omitted_files": [],
"system_cores": {"sony-playstation": ["pcsx_rearmed"],
"nintendo-nes": ["mesen"]},
"core_names": {"pcsx_rearmed": ["pcsx_rearmed"], "mesen": ["mesen"]}}
(listed / "retroarch.json").write_text(json.dumps(manifest))
(listed / "targets" / "retroarch.json").write_text(json.dumps(
{"bcm2711": {"cores": ["pcsx_rearmed"]}, "h700": {"cores": ["mesen"]}}))
return listed / "retroarch.json", payloads
class ScreenChoicesInstallWhatTheirFlagInstalls(unittest.TestCase):
"""A board chosen on Device and an emulator ticked on Emulators install,
file for file and byte for byte, what --target and --emulator install."""
def setUp(self):
patcher = mock.patch.object(install, "_mounted_cards", return_value=[])
patcher.start()
self.addCleanup(patcher.stop)
self.root = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
self.addCleanup(shutil.rmtree, self.root, True)
self.listed, self.copies = _parity_list(self.root)
self.manifest = json.loads(self.listed.read_text())
self.env = {**os.environ, "RETROBIOS_OS": "linux", "HOME": str(self.root),
install.OFFLINE_VARIABLE: "1"}
def run_install(self, argv: list[str]) -> dict[str, str]:
proc = subprocess.run(argv, env=self.env, capture_output=True, text=True,
timeout=120, check=False, stdin=subprocess.DEVNULL)
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
dest = Path(next(arg for arg in argv if arg.startswith("--dest=")).split("=", 1)[1])
return {path.relative_to(dest).as_posix(): hashlib.sha1(path.read_bytes()).hexdigest()
for path in dest.rglob("*") if path.is_file()}
def flag_run(self, name: str, *flags: str) -> dict[str, str]:
return self.run_install([sys.executable, str(REPO_ROOT / "install.py"),
"--platform=retroarch",
f"--dest={self.root / name / 'system'}",
f"--manifest={self.listed}", f"--from={self.copies}",
*flags, "--events", "--yes"])
def screen(self, name: str) -> install.TuiState:
"""Change, over the plan of the list as a check leaves it."""
state = install.TuiState(os_type="linux", home=self.root)
state.platform, state.dest = "retroarch", self.root / name / "system"
state.manifest, state.manifest_for = self.manifest, "retroarch"
state.manifest_path, state.manifest_given = self.listed, True
state.from_folders = [self.copies]
state.check = dict(CHECK)
state.stack = ["plan", "options"]
return state
def screen_run(self, state: install.TuiState) -> dict[str, str]:
return self.run_install(install.tui_argv(state, "install", sys.executable,
str(REPO_ROOT / "install.py")))
@staticmethod
def choose(state: install.TuiState, action: str, value: object = None) -> None:
rows = install.tui_rows(state)
state.focus[state.screen] = next(
index for index, row in enumerate(rows)
if row.action == action and (value is None or row.value == value))
def test_a_board_chosen_on_device_installs_what_target_installs(self):
targets = install._validate_targets(
json.loads((self.listed.parent / "targets" / "retroarch.json").read_text()))
everything = self.flag_run("all")
chosen = {}
for board in ("bcm2711", "h700"):
with self.subTest(board=board):
state = self.screen(f"screen-{board}")
self.choose(state, "device")
self.assertEqual(press(state, "enter"), [("targets", "retroarch")])
install.tui_receive(state, ("targets", "retroarch", targets, ""))
self.choose(state, "board", board)
press(state, "enter")
self.assertEqual(state.screen, "options")
chosen[board] = self.screen_run(state)
self.assertEqual(chosen[board],
self.flag_run(f"flag-{board}", "--target", board))
self.assertNotEqual(chosen[board], everything)
# The two boards' cores want other bytes at one destination.
self.assertNotEqual(chosen["bcm2711"]["shared.bin"], chosen["h700"]["shared.bin"])
def test_every_board_installs_what_every_board_installs(self):
targets = install._validate_targets(
json.loads((self.listed.parent / "targets" / "retroarch.json").read_text()))
state = self.screen("screen-every")
state.board_seen = ("retroarch", state.dest, "h700", True, True)
self.choose(state, "device")
press(state, "enter")
install.tui_receive(state, ("targets", "retroarch", targets, ""))
self.choose(state, "board", "")
press(state, "enter")
self.assertEqual(self.screen_run(state),
self.flag_run("flag-every", "--every-board"))
def test_an_emulator_ticked_installs_what_emulator_installs(self):
for emulator in ("mesen", "pcsx_rearmed"):
with self.subTest(emulator=emulator):
state = self.screen(f"screen-{emulator}")
self.choose(state, "emulators")
press(state, "enter")
self.choose(state, "emulator", emulator)
press(state, " ", "esc")
self.assertEqual(state.screen, "options")
chosen = self.screen_run(state)
self.assertEqual(chosen, self.flag_run(f"flag-{emulator}",
"--emulator", emulator))
# The files of its systems, and its own copy of the shared one.
shared = next(entry for entry in self.manifest["files"]
if entry["dest"] == "shared.bin")
self.assertEqual(chosen["shared.bin"], shared["sha1"] if emulator ==
"pcsx_rearmed" else shared["alternatives"][0]["sha1"])
self.assertNotIn("nes_plat.bin" if emulator == "pcsx_rearmed"
else "plat.bin", chosen)
class EmulatorChoiceMatchesTheEmulatorPack(unittest.TestCase):
"""An emulator ticked on Emulators against the pack generate_pack.py
--emulator builds for it, on the real lists: every file of the pack at
its destination with its bytes, and beside them only the files the
platform's own list names for the systems the emulator runs."""
CASES = (("retroarch", "handy"), ("retroarch", "beetle_psx"), ("retroarch", "mesen"),
("batocera", "mesen"), ("batocera", "handy"))
@classmethod
def setUpClass(cls):
db_path = REPO_ROOT / "database.json"
if not db_path.exists():
raise unittest.SkipTest("database.json is not built")
if sys.version_info < (3, 9):
# The builder's floor: install.py alone keeps 3.8.
raise unittest.SkipTest("generate_pack.py needs Python 3.9 or newer")
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import generate_pack as gp
from common import build_zip_contents_index
cls.gp = gp
cls.db = json.loads(db_path.read_text(encoding="utf-8"))
cls.zip_contents = build_zip_contents_index(cls.db)
cls.by_path = {entry["path"]: sha1 for sha1, entry in cls.db["files"].items()}
def pack(self, emulator: str) -> dict[str, str]:
record = self.gp.PackRecord()
with contextlib.redirect_stdout(io.StringIO()):
self.gp.generate_emulator_pack(
[emulator], str(REPO_ROOT / "emulators"), self.db, str(REPO_ROOT / "bios"),
str(REPO_ROOT / "tmp"), zip_contents=self.zip_contents, offline=True,
record=record)
return {member: self.by_path[record.sources[member]] for member in record.files}
def test_each_case(self):
for plat, emulator in self.CASES:
with self.subTest(platform=plat, emulator=emulator):
manifest = json.loads((REPO_ROOT / "install" / f"{plat}.json").read_text())
state = install.TuiState(os_type="linux")
state.platform, state.dest = plat, Path("/x/bios")
state.manifest, state.manifest_for = manifest, plat
state.stack = ["plan", "options", "emulators"]
rows = install.tui_rows(state)
state.focus["emulators"] = next(i for i, row in enumerate(rows)
if row.value == emulator)
press(state, " ")
argv = install.tui_argv(state, "install", "py", "install.py")
args = install.build_parser().parse_args(argv[2:])
self.assertEqual(args.emulator, [emulator])
with contextlib.redirect_stdout(io.StringIO()):
files, _omitted = install._narrow_to_emulators(
args.emulator, manifest, plat, manifest["files"],
manifest["omitted_files"])
installed = {entry["dest"]: entry["sha1"] for entry in files}
packed = self.pack(emulator)
self.assertTrue(packed)
self.assertEqual({dest: installed.get(dest) for dest in packed}, packed)
for dest in set(installed) - set(packed):
entry = next(entry for entry in files if entry["dest"] == dest)
self.assertIsNone(entry.get("cores"), dest)
if __name__ == "__main__":
unittest.main()