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>
This commit is contained in:
Cyd
2026-06-27 17:13:48 -05:00
co-authored by Claude Opus 4.8
parent 2deeb374ae
commit 8d2d0b71aa
47 changed files with 3866 additions and 21 deletions
@@ -0,0 +1,49 @@
"","","","","IMAGE NAME","","","","defalt","","","","Plasma greeting","","","","Hello,","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","","S","C","A","KEY","S","","A","KEY","S","C","A","KEY","S","C","A","KEY","","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY",""
"","","","","G_KEY","","","","H_KEY","","","","I_KEY","","","","J_KEY","","","","","K_KEY","","","","L_KEY","","","","M_KEY","","","","N_KEY","","","","","O_KEY","","","","P_KEY","","","","Q_KEY","","","","R_KEY",""
"","","LABEL","","G","","LABEL","","H","","LABEL","","I","","LABEL","","J","","","LABEL","","K","","","","L","","LABEL","","M","","LABEL","","N","","","LABEL","","O","","LABEL","","P","","LABEL","","Q","","LABEL","","R",""
"","IsLit","","","2F","IsLit","","","2E","IsLit","","","2D","IsLit","","","2C","","IsLit","","","27","IsLit","","","26","IsLit","","","25","IsLit","","","24","","IsLit","","","37","IsLit","","","36","IsLit","","","35","IsLit","","","34",""
"","x","","","","x","","","","x","","","","x","","","","","x","","","","x","","","","x","","","","x","","","","","x","","","","x","","","","x","","","","x","","","",""
"","IsLit","","","2B","IsLit","","","2A","IsLit","","","29","IsLit","","","28","","IsLit","","","23","IsLit","","","22","IsLit","","","21","IsLit","","","20","","IsLit","","","33","IsLit","","","32","IsLit","","","31","IsLit","","","30",""
"","x","","","","x","","","","x","","","","x","","","","","x","","","","x","","","","x","","","","x","","","","","x","","","","x","","","","x","","","","x","","","",""
"","","LABEL","","S","","LABEL","","T","","LABEL","","U","","LABEL","","V","","","LABEL","","<","","","","^","","LABEL","","v","","LABEL","",">","","","LABEL","","W","","LABEL","","X","","LABEL","","Y","","LABEL","","Z",""
"","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","","S","C","A","KEY","S","","A","KEY","S","C","A","KEY","S","C","A","KEY","","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY",""
"","","","","S_KEY","","","","T_KEY","","","","U_KEY","","","","V_KEY","","","","","LEFT","","","","UP","","","","DOWN","","","","RIGHT","","","","","W_KEY","","","","X_KEY","","","","Y_KEY","","","","Z_KEY",""
"","","","","KEYPAD","","","","LABELS","","","","JOYSTICK AIS","INVERT","","","","","S","C","A","KEY","KEY PAD","","","","BUTTONS","","","","S","C","A","KEY","","S","C","A","KEY","IsLit","","","THROTTLE BOARD","S","C","A","KEY","IsLit","","","JOYSTICK BOARD",""
"","","0","","0","","8","","8","","","","X","","","","","","","","","0_KEY","50","","","","58","","","","","","","8_KEY","","","","","MouseU","","","","38","","","","J1","","","","40",""
"","","1","","1","","9","","9","","","","Y","","","","","","","","","1_KEY","51","","","","59","","","","","","","9_KEY","","","","","MouseR","","","","39","","","","HatD","","","","41",""
"","","2","","2","","A","","A","","","","Z","","","","","","","","","2_KEY","52","","","","5A","","","","","","","A_KEY","","","","","MouseD","","","","3A","","","","HatU","","","","42",""
"","","3","","3","","B","","B","","","","R (L PEDDLE)","","","","","","","","","3_KEY","53","","","","5B","","","","","","","B_KEY","","","","","MouseL","","","","3B","","","","HatR","","","","43",""
"","","4","","4","","C","","C","","","","YR (R PEDDLE)","","","","","","","","","4_KEY","54","","","","5C","","","","","","","C_KEY","","","","","MouseLC","","","","3C","","","","HatL","","","","44",""
"","","5","","5","","D","","D","","","","ZR (RUDDER)","","","","","","","","","5_KEY","55","","","","5D","","","","","","","D_KEY","","","","","ESCAPE","x","","","3D","","","","J4","","","","45",""
"","","6","","6","","E","","E","","","","ZR (DISSABLE)","","","","","","","","","6_KEY","56","","","","5E","","","","","","","E_KEY","","","","","MouseRC","","","","3E","","","","J3","","","","46",""
"","","7","","7","","F","","F","","","","","","","","","","","","","7_KEY","57","","","","5F","","","","","","","F_KEY","","","","","J8","","","","3F","","","","J2","","","","47",""
"","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","","S","C","A","KEY","IsLit","","","SECONDARY","IsLit","","","SCREEN","S","C","A","KEY","","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY",""
"","","","","HOME","","","","COMMA","","","","PERIOD","","","","END","","","","","MouseU","X","","","10","X","","","18","","","","RETURN","","X","","","LEFT","X","","","RIGHT","X","","","DOWN","X","x","x","UP",""
"","","LABEL","","TOP CONTACT","","LABEL","","UP CONTACT","","LABEL","","DOWN CON","","LABEL","","LAST CONTACT","","","","","MouseR","X","","","11","X","","","19","","","","MENU(ALT)","","","LABEL","","OFFENCE","","LABEL","","DEFENCE","","LABEL","","DRIVE","","LABEL","","BALANCE",""
"","IsLit","","","0F","IsLit","","","0E","IsLit","","","0D","IsLit","","","0C","","","","","MouseD","X","","","12","X","","","1A","","","","CONTROL","","IsLit","","","07","IsLit","","","06","IsLit","","","05","IsLit","","","04",""
"","X","","","","X","","","","X","","","","X","","","","","","","","MouseL","X","","","13","X","","","1B","","","","SHIFT","","x","","","","x","","","","x","","","","x","","","",""
"","IsLit","","","0B","IsLit","","","0A","IsLit","","","09","IsLit","","","08","","","","","MouseLC","X","","","14","X","","","1C","","","","VOLUME_UP","","IsLit","","","03","IsLit","","","02","IsLit","","","01","IsLit","","","00",""
"","X","","","","X","","","","X","","","","X","","","","","","","","TAB","X","","","15","X","","","1D","","","","VOLUME_DOWN","","x","","","","x","","","","x","","","","x","","","",""
"","","LABEL","","NEAR ENEMY","","LABEL","","NEXT ENEMY","","LABEL","","SUB TARGET","","LABEL","","LAST AGGESSOR","","","","","NULL","","","","16","","","","1E","","","","NULL","","","LABEL","","LDS","","LABEL","","UNDOCK","","LABEL","","ZOOM","","LABEL","","LSDI",""
"","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","","","","","NULL","","","","17","","","","1F","","","","NULL","","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY","S","C","A","KEY",""
"","","","","R_KEY","","","","E_KEY","","","","Y_KEY","","","","Q_KEY","","","","","","","","","SECONDARY","","","","LABELS","","","","","","","","","L_KEY","","","","U_KEY","","","","Z_KEY","","","","I_KEY",""
"","","","","","","","","","","","","","","","","","","","","","","","10","","M U","","18","","ENTER","","","","","","","","","THROTTLE LABELS","","","","","","","","JOYSTICK LABELS","","","","",""
"","S","C","A","KEY","EXTERNAL KEY PAD","","","","BUTTONS","","","","S","C","A","KEY","","","","","","","11","","M R","","19","","ALT","","","","","","","38","","M ^","","","","","","40","","FIRE/ACCEPT","","","","",""
"","","","","RIO_AnalogAllReset","60","","","","68","","","","","","","RIO_AxesReadout","","","","","","","12","","M D","","1A","","CTRL","","","","","","","39","","M >","","","","","","41","","H v","","","","",""
"","","","","RIO_ResetThrottle","61","","","","69","","","","","","","RIO_FrequencyReadout","","","","","","","13","","M L","","1B","","SHIFT","","","","","","","3A","","M v","","","","","","42","","H ^","","","","",""
"","","","","RIO_ResetLeftPedal","62","","","","6A","","","","","","","RIO_more1","","","","","","","14","","MLC","","1C","","VL U","","","","","","","3B","","M <","","","","","","43","","H >","","","","",""
"","","","","RIO_ResetRightPedal","63","","","","6B","","","","","","","RIO_more2","","","","","","","15","","TAB","","1D","","VL D","","","","","","","3C","","ML","","","","","","44","","H <","","","","",""
"","","","","RIO_ResetVerticalJoystick","64","","","","6C","","","","","","","RIO_more3","","","","","","","16","","","","1E","","","","","","","","","3D","","ESC","","","","","","45","","NEXT PRIMEARY","","","","",""
"","","","","RIO_ResetHorizontalJoystick","65","","","","6D","","","","","","","RIO_more4","","","","","","","17","","","","1F","","","","","","","","","3E","","MR","","","","","","46","","NEXT SECOND","","","","",""
"","","","","RIO_DigitalReset","66","","","","6E","","","","","","","RIO_more5","","","","","","","","","","","","","","","","","","","","3F","","REVERSE","","","","","","47","","TARGET/BACK","","","","",""
"","","","","RIO_StatusCheck","67","","","","6F","","","","","","","RIO_more6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","","","EXT KEYPAD","","","","LABLES","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","0","","RIO_0","","8","","RIO_8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","1","","RIO_1","","9","","RIO_9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","2","","RIO_2","","A","","RIO_A","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","3","","RIO_3","","B","","RIO_B","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","4","","RIO_4","","C","","RIO_C","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","5","","RIO_5","","D","","RIO_D","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","6","","RIO_6","","E","","RIO_E","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","7","","RIO_7","","F","","RIO_F","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""
1 IMAGE NAME defalt Plasma greeting Hello,
2 S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY S A KEY S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY
3 G_KEY H_KEY I_KEY J_KEY K_KEY L_KEY M_KEY N_KEY O_KEY P_KEY Q_KEY R_KEY
4 LABEL G LABEL H LABEL I LABEL J LABEL K L LABEL M LABEL N LABEL O LABEL P LABEL Q LABEL R
5 IsLit 2F IsLit 2E IsLit 2D IsLit 2C IsLit 27 IsLit 26 IsLit 25 IsLit 24 IsLit 37 IsLit 36 IsLit 35 IsLit 34
6 x x x x x x x x x x x x
7 IsLit 2B IsLit 2A IsLit 29 IsLit 28 IsLit 23 IsLit 22 IsLit 21 IsLit 20 IsLit 33 IsLit 32 IsLit 31 IsLit 30
8 x x x x x x x x x x x x
9 LABEL S LABEL T LABEL U LABEL V LABEL < ^ LABEL v LABEL > LABEL W LABEL X LABEL Y LABEL Z
10 S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY S A KEY S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY
11 S_KEY T_KEY U_KEY V_KEY LEFT UP DOWN RIGHT W_KEY X_KEY Y_KEY Z_KEY
12 KEYPAD LABELS JOYSTICK AIS INVERT S C A KEY KEY PAD BUTTONS S C A KEY S C A KEY IsLit THROTTLE BOARD S C A KEY IsLit JOYSTICK BOARD
13 0 0 8 8 X 0_KEY 50 58 8_KEY MouseU 38 J1 40
14 1 1 9 9 Y 1_KEY 51 59 9_KEY MouseR 39 HatD 41
15 2 2 A A Z 2_KEY 52 5A A_KEY MouseD 3A HatU 42
16 3 3 B B R (L PEDDLE) 3_KEY 53 5B B_KEY MouseL 3B HatR 43
17 4 4 C C YR (R PEDDLE) 4_KEY 54 5C C_KEY MouseLC 3C HatL 44
18 5 5 D D ZR (RUDDER) 5_KEY 55 5D D_KEY ESCAPE x 3D J4 45
19 6 6 E E ZR (DISSABLE) 6_KEY 56 5E E_KEY MouseRC 3E J3 46
20 7 7 F F 7_KEY 57 5F F_KEY J8 3F J2 47
21 S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY IsLit SECONDARY IsLit SCREEN S C A KEY S C A KEY S C A KEY S C A KEY S C A KEY
22 HOME COMMA PERIOD END MouseU X 10 X 18 RETURN X LEFT X RIGHT X DOWN X x x UP
23 LABEL TOP CONTACT LABEL UP CONTACT LABEL DOWN CON LABEL LAST CONTACT MouseR X 11 X 19 MENU(ALT) LABEL OFFENCE LABEL DEFENCE LABEL DRIVE LABEL BALANCE
24 IsLit 0F IsLit 0E IsLit 0D IsLit 0C MouseD X 12 X 1A CONTROL IsLit 07 IsLit 06 IsLit 05 IsLit 04
25 X X X X MouseL X 13 X 1B SHIFT x x x x
26 IsLit 0B IsLit 0A IsLit 09 IsLit 08 MouseLC X 14 X 1C VOLUME_UP IsLit 03 IsLit 02 IsLit 01 IsLit 00
27 X X X X TAB X 15 X 1D VOLUME_DOWN x x x x
28 LABEL NEAR ENEMY LABEL NEXT ENEMY LABEL SUB TARGET LABEL LAST AGGESSOR NULL 16 1E NULL LABEL LDS LABEL UNDOCK LABEL ZOOM LABEL LSDI
29 S C A KEY S C A KEY S C A KEY S C A KEY NULL 17 1F NULL S C A KEY S C A KEY S C A KEY S C A KEY
30 R_KEY E_KEY Y_KEY Q_KEY SECONDARY LABELS L_KEY U_KEY Z_KEY I_KEY
31 10 M U 18 ENTER THROTTLE LABELS JOYSTICK LABELS
32 S C A KEY EXTERNAL KEY PAD BUTTONS S C A KEY 11 M R 19 ALT 38 M ^ 40 FIRE/ACCEPT
33 RIO_AnalogAllReset 60 68 RIO_AxesReadout 12 M D 1A CTRL 39 M > 41 H v
34 RIO_ResetThrottle 61 69 RIO_FrequencyReadout 13 M L 1B SHIFT 3A M v 42 H ^
35 RIO_ResetLeftPedal 62 6A RIO_more1 14 MLC 1C VL U 3B M < 43 H >
36 RIO_ResetRightPedal 63 6B RIO_more2 15 TAB 1D VL D 3C ML 44 H <
37 RIO_ResetVerticalJoystick 64 6C RIO_more3 16 1E 3D ESC 45 NEXT PRIMEARY
38 RIO_ResetHorizontalJoystick 65 6D RIO_more4 17 1F 3E MR 46 NEXT SECOND
39 RIO_DigitalReset 66 6E RIO_more5 3F REVERSE 47 TARGET/BACK
40 RIO_StatusCheck 67 6F RIO_more6
41 EXT KEYPAD LABLES
42 0 RIO_0 8 RIO_8
43 1 RIO_1 9 RIO_9
44 2 RIO_2 A RIO_A
45 3 RIO_3 B RIO_B
46 4 RIO_4 C RIO_C
47 5 RIO_5 D RIO_D
48 6 RIO_6 E RIO_E
49 7 RIO_7 F RIO_F
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB