Skip to content

feat(ui): per-slot card configuration -- any supported card in any slot, with period-typical defaults #124

Description

@relmer

Summary

Make each slot's occupant user-selectable: a dropdown in the Slots section of the Hardware tab offering any supported card for any slot, with default assignments modeling where people actually installed each card in period.

An Apple II slot is generic. Fixing each card to one slot per machine profile is the thing that's actually unfaithful.

Background

Today the Hardware tab renders slots as a checkbox tree — a slot's card can be enabled or removed, but not changed. Which card lives in which slot is baked into the machine profile JSON:

Profile Slot 1 Slot 4 Slot 6
Apple ][ parallel-printer disk-ii
Apple ][+ / //e / //e Enhanced parallel-printer mockingboard disk-ii

The emulation layer is already slot-agnostic — every card takes its slot from config and computes its own $Cn00 base:

  • Disk2Controller::Createconfig.hasSlot ? config.slot : 6
  • PrinterCard::Create — defaults to 1
  • Acia6551::Create — derives its base from config.slot
  • MockingboardCard::Create — passes the slot straight through

Nothing hardcodes a slot. "Any card in any slot" is already true below the UI.

Scope

1. Card descriptors in the registry. ComponentRegistry is typeName -> FactoryFunc and nothing else. Populating a dropdown needs per-type metadata: display name ("Mockingboard C (sound + speech)", not "mockingboard"), which slots are legal, whether duplicates are allowed, whether a slot ROM is required, and a recommended default slot.

2. Slot composition becomes user-editable state. This is the substantive change. SettingsPanelState::BuildJson rebuilds the slots array from the machine profile with only the enabled bit overlaid — the device string is cloned verbatim, and SetHardwareEnabled is the only mutator. Making the occupant editable means the override JSON starts carrying slot composition, which touches the merge, the dirty check, and the reset-required rule.

3. An in-row dropdown in the tree. DxuiTreeView paints checkboxes and capability flags. An interactive dropdown inside a tree row is real Dxui work, and its popup must escape the page's clipping bounds — HardwarePage already solves that for the machine and speed dropdowns via SetPopupHost, so there's a pattern to follow, though a tree row is a harder host than a fixed-position control.

4. Period-typical defaults. Slot assignments that model where cards actually went — printer in 1, Mockingboard in 4, Disk II in 6 — so the out-of-box machine matches what software expects and the dropdown is an override rather than a requirement.

Constraints worth surfacing rather than enforcing

The hardware doesn't restrict placement; software convention does, and that's a UX problem rather than a correctness one:

  • Convention is load-bearing. Mockingboard players overwhelmingly assume slot 4, DOS/ProDOS boot assumes slot 6, printer drivers assume slot 1. A user who moves the Mockingboard to slot 5 gets a silent machine and no explanation. Prefer a "recommended slot" hint over a hard restriction.
  • The //c has no slots. Its equivalents are soldered down. CapabilityFlag::PlatformLocked + lockReason already exist for exactly this — the dropdown should be absent or locked there.
  • The shell caches one pointer per card type. EmulatorShell holds a single diskController / mockingboard / etc. A free dropdown permits configurations that were legal on real hardware but that this wiring doesn't expect — two Mockingboards (people genuinely did this), or a Disk II in slot 3. Either constrain duplicates in the descriptor or teach the shell to resolve by type across slots.

Relationship to the Mockingboard C work

This is where a user picks between the Mockingboard A and the Mockingboard C. That work does not depend on this issue — it selects its variant by machine configuration — but this is what exposes the choice properly, alongside every other card.

Sizing note: the candidate list today is four cards plus "empty". The payoff grows as cards are added, which the disk specs (020/021/022) and the platform roadmap will do.

Acceptance Criteria

  • Every slot in the Hardware tab offers a dropdown listing the cards legal for that slot, plus "empty"
  • Default assignments match period-typical install locations, and a fresh profile is unchanged from today's behavior
  • A card moved to a non-default slot is reachable by software at that slot's $Cn00 page
  • The recommended slot for each card is discoverable in the UI, so a user moving a card away from it understands the risk
  • Slot composition persists across sessions and survives a machine switch and back
  • Changing a slot's occupant reports that a machine reset is required, consistent with existing hardware-configuration changes
  • The //c presents no slot dropdowns, with its locked entries explaining why
  • Duplicate cards are either supported end-to-end or refused with a clear reason — not silently half-wired
  • Machine profile JSON remains the source of defaults; user overrides layer on top without rewriting the profile

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestimpact: userEmulator end user: running Apple II softwarepriority: mediumReal value, niche or polish (end-user-value triage)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions