Files
riojoy/src/RioJoy.Core/Profiles/RioProfile.cs
T
CydandClaude Opus 4.8 8d2d0b71aa Phase 7: cockpit overlay generator, region extraction, and profile editor
Overlay generator (pure, tested) — RioJoy.Core/Overlay:
- FontFitter ports the legacy calc-fontsize auto-fit search (validated against a
  brute-force oracle); OverlayLayoutEngine ports create-data-layer's fit + h/v
  justification and adds per-region 90 deg CCW rotation; OverlayTemplate/Region +
  OverlayTemplateStore hold cell geometry/colour/rotation (regions.json).
- GoobieDataImporter parses the legacy .data label sheet into label rows.
- src/RioJoy.Overlay: SkiaSharp rasterizer (SkiaTextMeasurer shared with the engine
  so measured layout == drawn output; SkiaOverlayRenderer -> PNG;
  ProfileWallpaperGenerator). Verified end-to-end on the real cockpit art
  (regions.json + riojoy.png + TEST.data) by OverlayRenderIntegrationTests.
- RioJoy.Tray/WallpaperApplier applies via SystemParametersInfo; RioCoordinator
  generates+applies on profile activation (opt-in via AppConfig.OverlayTemplatePath).

Region geometry — tools/XcfRegionExtract parses riojoy.xcf (a GIMP-format binary
reader, no GIMP needed) into the 119-cell regions.json: per-layer offsets/size/
font/colour, with 90 deg CCW rotation on a-00 + b-10..b-1F. Base image riojoy.png.
NOTE: the wallpaper positions are a VGA chroma-split display artifact (6 displays),
not the cockpit's logical layout.

Mapping editor (first cut) — RioJoy.Tray/Editor/ProfileEditorForm renders the
config sheet's logical grid (SheetLayout parses the sheet CSV export). The iRIO
word is edited via ButtonBinding <-> RioMapEntry.Create (no hex bit-twiddling), with
a context-sensitive picker: keyboard keys by name (KeyCatalog VK names), joystick
Button N, hat direction, mouse/RIO-command enum names; modifiers only for keyboard.
Opened from the tray ("Edit profile..."). The sheet-grid layout is a starting point
that needs rework from a better-formatted source.

~220 xUnit tests green. Docs (PLAN.md, README) updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:13:48 -05:00

61 lines
2.4 KiB
C#

using RioJoy.Core.Calibration;
using RioJoy.Core.Mapping;
namespace RioJoy.Core.Profiles;
/// <summary>
/// A per-game profile: everything about how the cockpit behaves for one
/// non-native game (see docs/PLAN.md §Profiles). The unified profile supersedes
/// the legacy single-file <c>RIO.ini</c>. Profiles never describe the native
/// games — those are the hands-off/yield case.
/// </summary>
public sealed class RioProfile
{
/// <summary>Display name (unique within a library).</summary>
public string Name { get; set; } = "Unnamed";
/// <summary>RIO serial port (e.g. "COM3"); null = use the app default.</summary>
public string? RioComPort { get; set; }
/// <summary>Plasma/VFD serial port; null = use the app default or none.</summary>
public string? PlasmaComPort { get; set; }
/// <summary>
/// The <c>iRIO</c> map: RIO address (0x00..0x6F) → 16-bit map word. Only
/// mapped addresses need entries.
/// </summary>
public Dictionary<int, int> Buttons { get; set; } = new();
/// <summary>Axis calibration / invert options.</summary>
public AxisCalibrationConfig Calibration { get; set; } = new();
/// <summary>Plasma greeting text shown on load (null = leave display as-is).</summary>
public string? PlasmaGreeting { get; set; }
/// <summary>Cockpit wallpaper image path (generated in Phase 7).</summary>
public string? WallpaperPath { get; set; }
/// <summary>
/// Overlay label text per template region (region/layer name → display text,
/// e.g. <c>"b-00" → "FIRE"</c>). Drives the Phase 7 wallpaper generator
/// (<see cref="Overlay.OverlayLayoutEngine"/>); empty/absent entries render
/// nothing. The region geometry itself lives in the shared overlay template.
/// </summary>
public Dictionary<string, string> OverlayLabels { get; set; } = new();
/// <summary>
/// Executable names that select this profile when they are the foreground app
/// (matched case-insensitively, with or without ".exe").
/// </summary>
public List<string> MatchExecutables { get; set; } = new();
/// <summary>Build a <see cref="RioInputMap"/> from <see cref="Buttons"/>.</summary>
public RioInputMap ToInputMap()
{
var map = new RioInputMap();
foreach ((int address, int raw) in Buttons)
map[address] = new RioMapEntry((ushort)raw);
return map;
}
}