Files
Jean-Pierre MartineauandClaude Opus 5.5 3e251a9707 Docstrings and comments of meshterm/emulator are in ASD-STE100
The same rewrite as for the core package. The physical screen of a
handheld is now the display, and the computer is the handheld. The
comment on FONT_ENV now says that it is the environment variable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 03:51:55 -04:00

116 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPDX-License-Identifier: Apache-2.0
"""The handhelds that the emulator can act as, and what the emulator copies of each.
A handheld here is its display and its keyboard, as MeshTerm meets them. That is the
platform that MeshTerm runs as on it, the size of the display in pixels, how a console
draws on that display, and which desktop keyboard keys act as its lane keys. It is never
its processor or its operating system (refer to :mod:`meshterm.emulator`). The id of each
handheld is the id of its platform. Thus ``meshterm emulate picocalc-lyra`` and
``--platform picocalc-lyra`` name the same handheld.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
from prompt_toolkit.output.color_depth import ColorDepth
from ..platforms import CARDPUTER_ZERO, PICOCALC_LYRA, Platform
from .keys import Key
if TYPE_CHECKING:
from ..ui.tui.fkeys import LaneDeck
@dataclass(frozen=True)
class EmulatedDevice:
"""The display and the keyboard of one handheld, as the emulator copies them.
Attributes:
platform: The platform that MeshTerm runs as on the handheld. Its grid is the grid
of the display.
name: The usual name of the handheld, for the title of the window.
panel: The size of the display in pixels, ``(width, height)``.
console: Whether a Linux console draws the screen of the handheld, instead of
MeshTerm in truecolour. A console puts the grid at the top-left of the
display, shows bold as bright, uses palette slot 7 on slot 0 as the default
colours, and sends sixteen colours.
lane_keys: The keyboard keys under the display that drive the F-key lane, as
``(label, centre)`` pairs in display pixels: one for each slot of the
:attr:`deck`, from left to right. The window draws them under its display, so
that a chip that moves away from its keyboard key is visible. The user can
press them there with the mouse. Empty for a handheld whose lane keys are at
a different place.
shifted: The Shift+F-key of the desktop, mapped to the keyboard key that the
keyboard of the handheld sends instead. The PicoCalc's keyboard sends F6–F10
for Shift+F1–F5. The Cardputer Zero's keyboard sends a shifted F4–F8, for
which no translation is necessary.
"""
platform: Platform
name: str
panel: tuple[int, int]
console: bool = False
lane_keys: tuple[tuple[str, int], ...] = ()
shifted: dict[str, str] = field(default_factory=dict)
@property
def id(self) -> str:
"""The id of the handheld: the name of its platform (``picocalc-lyra``)."""
return self.platform.name
@property
def color_depth(self) -> ColorDepth:
"""What prompt_toolkit can send: sixteen colours to a console, else truecolour."""
return ColorDepth.DEPTH_4_BIT if self.console else ColorDepth.TRUE_COLOR
@property
def deck(self) -> LaneDeck:
"""The F-key lane deck of the platform of the handheld (:mod:`~meshterm.ui.tui.fkeys`)."""
from ..ui.tui.fkeys import DECKS
return DECKS[self.platform.lane_deck]
def translate(self, key: Key) -> Key:
"""The keyboard key as the keyboard of the handheld sends it (refer to :attr:`shifted`)."""
if key.shift and key.name in self.shifted:
return Key(name=self.shifted[key.name], ctrl=key.ctrl, alt=key.alt)
return key
#: M5Stack's Cardputer Zero: a 320×170 display that MeshTerm draws itself. Its lane is on
#: Fn+4…8, the five keyboard keys directly under the display, at the positions that the
#: drawing from M5 gives them.
CARDPUTER_ZERO_DEVICE = EmulatedDevice(
platform=CARDPUTER_ZERO,
name="Cardputer Zero",
panel=(320, 170),
lane_keys=(("4", 48), ("5", 104), ("6", 160), ("7", 216), ("8", 272)),
)
#: ClockworkPi's PicoCalc with a Luckfox Lyra core: a 320×320 display that the Linux
#: console draws in 6×12 cells. Its lane is on F1–F5, and Shift sends F6–F10.
PICOCALC_LYRA_DEVICE = EmulatedDevice(
platform=PICOCALC_LYRA,
name="PicoCalc (Luckfox Lyra)",
panel=(320, 320),
console=True,
shifted={f"f{n}": f"f{n + 5}" for n in range(1, 6)},
)
#: All the handhelds that the emulator offers, by id.
DEVICES: dict[str, EmulatedDevice] = {
device.id: device for device in (CARDPUTER_ZERO_DEVICE, PICOCALC_LYRA_DEVICE)
}
def device(name: str) -> EmulatedDevice:
"""The handheld called ``name``, or a ``ValueError`` that names the available ones."""
try:
return DEVICES[name.strip().lower()]
except KeyError:
raise ValueError(
f"no emulated device {name!r} - choose from: {', '.join(sorted(DEVICES))}"
) from None