wish.window¶
The tabbed window: the character editor and the live map, in one place.
Both tabs are the windows that already existed, unchanged in what they do. They
are QMainWindow`s used as pages, which Qt allows and which is what keeps this
file thin: the editor's form, bindings and losslessness rules are untouched, and
the map still paints exactly what `render.py gives it.
What the outer window adds is the three things a merged application owes you:
one connection.
wish/session.pyowns it, because VICE serves exactly one binary-monitor connection and ignores the second in silence.one status bar, answering “what am I looking at” – the file on the editor tab, the connection and the party’s square on the map tab.
one title, carrying the open save and a dirty marker whichever tab shows.
The editor tab is never handed the target. That is the project’s first decision
made structural (docs/README.md): editor/ imports nothing from automap/, and the
file path works with no emulator anywhere.
Module Attributes
Said in the Messages panel when |
|
|
|
The first run's size, when nothing has been remembered yet. |
Functions
|
The application's name and its icon, before the first window exists. |
|
Every GEO off the game disks, or nothing if they cannot be found. |
|
The maps and their title, or nothing at all. |
|
Classes
The application window. |
- wish.window.ANY_BACKEND = ''¶
backends.findtakes whichever answers first. The ordinary case, and what an emptySettings.backendmeans.- Type:
No preference
- wish.window.FIRST_RUN = (1875, 1030)¶
The first run’s size, when nothing has been remembered yet. Wide enough for the map, the roster cards and the notes column side by side; clamped to the screen, so a smaller display gets its own size rather than this one.
- wish.window.SWITCHED_TITLE = 'Now mapping {title}.'¶
Said in the Messages panel when
#357 (The automapper reads the shared Game disks folder, so setting a title's own folder does not make it map that title)step 4 switches the window to a title the machine turned out to be running, rather than refusing. Approved by Donald, 2026-09-07, chosen over two longer wordings that named the disks or the folder: the line says the thing a player wants to know – the automapper is on this title now – and leaves the reason it changed to the debug log beside it.
- class wish.window.WishWindow[source]¶
Bases:
PyQt6.QtWidgets.QMainWindowThe application window.
- __init__(save=None, game_disk=None, maps=None, area=None, settings=None, session=None, tab=MAP_TAB, title=None, disks=None)[source]¶
- Parameters:
save (str | None)
game_disk (str | None)
maps (dict | None)
area (str | None)
settings (automap.config.Settings | None)
session (wish.session.Session | None)
tab (int)
title (str | None)
disks (str | None)
- closeEvent(event)[source]¶
The editor asks about unsaved changes first, and may refuse.
Its own
closeEventowns that question – the merged window must not grow a second copy of it and get the two out of step.- Return type:
None
- disks_text()[source]¶
The resolved Game directory as a plain path, for the two tabs.
- Return type:
str | None
- follow_save()[source]¶
A save was opened: point the automatic backup folder at it, and remember its folder for the next
File > Open(#66).The backup half does nothing at all once the user has chosen a folder in the dialog – “never change it after they’ve specified it themselves” – but the remembered-folder half always follows: it is a convenience, not a preference, so every open updates it.
- Return type:
None
- label_backends()[source]¶
Say which are answering, when the dialog asks and not before.
probe()is a TCP connect with a short timeout; doing it on the poll timer would be noise, and doing it once at startup would be stale by the time anybody looked.The state is also kept in
backend_status, apart from the label: the dialog draws it as a badge, because on Windows “Ultimate not answering, unverified…” ran into its own label as one sentence.- Return type:
None
- map_game()[source]¶
Which title the automapper is labelling with, as a
Game.Not `game()`, which is the open save’s and is None with nothing open. The fast-travel list has to agree with the map, and the map always has a title – it falls back through the open save, the disks folder and
games.DEFAULT(docs/138-multiple-games.md§3). A list keyed off anything else would offer one game’s areas in another’s session, which is the whole of #14.
- observe_title(title)[source]¶
The machine is drawing a different configured title’s map.
#357 (The automapper reads the shared Game disks folder, so setting a title's own folder does not make it map that title)step 4, Donald’s ruling of 2026-09-07: switch to it rather than refuse, and say so. Settingself._titlebeforereload_disksis the whole of the mechanism –game()reads it,resolve_disksasksgame_foldersfor that title’s own row, andAutomapBinding.set_maps(called fromreload_disks) takestitle_checkback toUNKNOWNand re-applies the per-title controls for the new title.- Parameters:
title (str)
- Return type:
None
- preferences()[source]¶
File > Preferences. Returns the dialog, which is what a test wants.
- Return type:
- reload_disks()[source]¶
Re-resolve where the disks are and hand the answer to both tabs.
- Return type:
None
- set_backup_folder(folder)[source]¶
The user typed, browsed or cleared one in the dialog.
Anything they typed is theirs and is never moved again. Clearing it is the way back to automatic: a setting a user cannot undo is a trap, and the field fills in again from the open save – immediately when there is one, otherwise the next time one is opened.
- Parameters:
folder (str)
- Return type:
None
- set_fast_travel_targets(ids)[source]¶
Which areas the Fast Travel dropdown offers, by
goldbox/areas.pyid.Empty is a choice like any other and is saved as one: the setting is None only until somebody has ticked or unticked anything. Filed under the open title’s key, because an area id means nothing without one.
- Return type:
None
- set_interval(interval_ms)[source]¶
How often to poll, or 0 for the backend’s own.
- Parameters:
interval_ms (int)
- Return type:
None
- set_saves_folder(folder)[source]¶
The user typed, browsed or cleared the saves folder in the dialog (#66 steps 2 and 3).
Unlike the backup folder above, this has no automatic state to fall back to: it is either set or it is not, and clearing it goes back to the folder a save was last opened from, or beside the one already open.
- Parameters:
folder (str)
- Return type:
None
- set_ultimate_host(host)[source]¶
Where the Commodore 64 Ultimate is. Empty means “no device”.
- Parameters:
host (str)
- Return type:
None
- wish.window.dress(app)[source]¶
The application’s name and its icon, before the first window exists.
Three separate mechanisms, one drawing:
`setWindowIcon` is the title bar, Alt-Tab and the taskbar button of a running window. It is a
QIconcarrying a pixmap per size, painted fromui/icons.py, so Qt picks rather than scales. What a pinned shortcut and Explorer show is the.icoin the executable’s resource instead –wish.spec– and the two have to be the same drawing, which they are because both come from the same path data.`setDesktopFileName` is how GNOME and KDE match a window to its
.desktopentry, and without it a Wayland window gets the toolkit’s generic icon whateversetWindowIconsaid.wishis the id the freedesktop icons underassets/icons/hicolorare named for.the app user model id is Windows’ key for taskbar grouping and pinning. Left unset, a Python-hosted window can be grouped under the interpreter rather than under itself, and a pin can attach to the wrong thing.
And on Linux, none of that is enough on its own. The desktop matches the window to a
.desktopentry and then looks up the icon by name in its icon theme, so with neither installed it draws a generic gear whateversetWindowIconsaid. Donald hit exactly that on 2026-09-05. A wheel ships both into<prefix>/share, which is on the search path for apip install --userand not for a virtualenv or apipxinstall – sotools.installdesktop.ensureputs them in the user’s own directory the first time it finds none. It refuses to run on anything but Linux, when an entry already exists anywhere on the search path, whenWISH_NO_DESKTOP_INSTALLis set, and in a headless or offscreen run – the last of which is what keeps the test suite out of somebody’s home directory.- Return type:
None
- wish.window.load_maps(disks=None)[source]¶
Every GEO off the game disks, or nothing if they cannot be found.
- wish.window.load_maps_titled(disks=None, game=None)[source]¶
The maps and their title, or nothing at all.
Nothing here is fatal: with no disks the map tab draws an empty grid and says so, and the editor tab does not care at all. A truncated download sitting in the folder is the same – a reason to draw no map, not a reason to take the window down when somebody points the preference at it.