Pick a real camera with a set format and the FMT dial locks to it; custom gear stays free.
Where to find it
ViewfinderFMT dial; follows EquipmentCamera Body (Gear mode)
Summary
While gear drives the ranges (Gear mode), a bundled catalogue body whose format the app can resolve (a Hasselblad shoots 6x6, a Nikon F shoots 35mm, a Sinar shoots 4x5, a Fuji GX617 shoots 6x17) pins the FMT dial on the main viewfinder: the dial snaps to that format and goes read-only, so the negative size always matches the body in hand. Bodies with two gates keep the dial live on just those: the XPan family (XPan, XPan II, Fuji TX-1 and TX-2) on 35mm and 24x65, landing on 24x65 when picked, and the Mamiya 7 and 7 II on 6x7 and 24x65 (Mamiya's 35mm panoramic kit), landing on 6x7 (see 10.16). Custom mode leaves the dial free even with a body picked, and custom or cine bodies never pin it, nor do the few catalogue bodies that shoot a size the dial has no setting for (half-frame, APS, 127), so you can always set the format by hand when the body does not dictate one. Swiping between equipment presets flips the lock on and off as the active body changes.
How it works
In Gear mode, choose a camera that only ever shoots one format, like a Hasselblad 500C/M, and the app sets the FMT dial to 6x6 and locks it. Format is a property of the body, not a choice: a 6x6 Hasselblad cannot suddenly shoot 6x7, so the dial dims to show it is fixed. The same holds for a 35mm SLR (locked to 35mm), a 4x5 view camera, or a Fuji GX617 (locked to 6x17).
Cameras with two gates
The Hasselblad XPan, the XPan II and their Fuji twins, the TX-1 and TX-2, shoot 35mm or 24x65 on the same roll. Pick one and the dial jumps to 24x65 but stays live, offering just those two. Turn it to 35mm and it stays there, through a relaunch or a trip to Custom mode, until another body takes over. A Mamiya 7 or 7 II works the same way with 6x7 and 24x65, the frame its 35mm panoramic adapter kit gives, except that it starts on 6x7.
When the dial stays free
Two cases leave FMT completely free. First, Custom mode: switch the ranges to Custom and the body steps aside, so you can dial any format by hand even with a Hasselblad picked. Second, a body you added yourself stores only a broad format like 'medium' (it could be 6x4.5, 6x6, 6x7, or 6x9), so the app cannot pin it and leaves the dial live.
Swiping between presets
Say preset one is your Hasselblad and preset two is a custom rig. Swipe from one to the other and the lock follows: fixed on the Hasselblad, free on the custom body. The dial always tracks whatever camera is active, so you are never left on the wrong negative size.
Implementation notes
(for developers)
Since 10.16 the rule lives in model/FormatLock.kt: CameraSpec.formatLock is Free (custom bodies, cine, sizes without a gate), Pinned(format) (any other catalogue body with a filmFormat) or Choice(allowed, default) (CameraSpec.gateChoice, looked up by mount in the MULTI_GATE_MOUNTS table: 'hasselblad xpan' allows 35mm + 24x65 with default 24x65, 'mamiya 7' allows 24x65 + 6x7 with default 6x7; a new multi-gate family is one table entry). activeFormatLock(rangesMode, body) adds the gate: anything but GEAR_BASED is Free. CameraSpec.pinsFilmFormat = formatLock is Pinned. ClassicControls and PaperControls take formatLock = activeFormatLock(rangesMode, camera(gearCameraId)), feed the FMT RotaryDial items = formatLock.dialItems(selectedFormat) (every format, or a Choice's set plus the current format if something outside it was applied) and enabled = !formatLock.isReadOnly (alongside the measured-preview freeze), and dim it when read-only. The rangesMode == GEAR_BASED clause is essential: gearCameraId persists across the Gear/Custom toggle, so without it the lock leaks into Custom mode where the user is meant to be able to tweak FMT. RotaryDialStrip passes userScrollEnabled = enabled so the strip style honours the gate too (also fixes a latent freeze leak). onGearCameraChanged (bodyChanged = id != gearCameraId; the body picker only exists on the Gear tab), applyPresetToState (presetFilmFormat: only when the preset's own rangesMode is GEAR_BASED, so a Custom preset with a dormant body id leaves FMT alone, iOS ANDROID_ISSUES_FOUND row 68; bodyChanged = preset body != current body) and onRangesModeChanged into Gear (bodyChanged = false) land on CameraSpec.formatOnPick(current, bodyChanged): a Choice body keeps the current format while it stays active and the format is allowed, else its default; every other body returns filmFormat exactly as before. restoreSettings uses restoredFilmFormat(saved, savedMode, body): only a GEAR_BASED save lets the body override, Pinned forces its format, Choice keeps an allowed saved format. The shared onFormatSelected setter is left unguarded because the Framing compare-lens-kit paths call it internally. filmFormat reads the catalogue's exact sizes as well as the coarse families: '120 (6x4.5)', '(6x6)', '(6x7)', '(6x9)' and '(6x17)' map straight to their FilmFormat, '120 (6x8)' takes 6x9 (as the GX680 'medium' entries always did), '4x5' is LARGE_4x5, '24x65' (custom bodies) is PANORAMIC_24x65, a multi-gate mount returns its table default (XPan 24x65, Mamiya 7 6x7), and half-frame 35mm, APS and 127 return null so the dial stays free. CameraSpec.formatModeOf is the single string-to-family mapping, shared by the picker scope and ensureCustomEntryVisible. Lenses scope with the bodies that take their mount: GearRepository applies lensScopesFromBodies (one family per mount when every body using it agrees, so PL with 16mm and 35mm bodies is left out) through LensSpec.withBodyScope, and LensSpec.formatMode falls back to the hand-written mount lists, which now also name the 18 medium-format mounts (73 lenses: Mamiya 645 AF, Pentax 645, Contax 645, Fuji GX680, Mamiya 6 and 7, Fuji G, Bronica S and RF, the fixed TLR and Fuji ones) that used to sit in the 35mm tab; the Rollei 16 fixed lens follows its 16mm body to Cine. LensScopeTest walks lenses.json against cameras.json. Until 2026-10-25 the 140 bodies using those spellings fell through to the 35mm scope and never pinned; CameraSpecFormatLockTest now fails if cameras.json gains a format string the parser does not know, and FormatLockTest walks every multi-gate and 6x17 body in the catalogue.