emulator: B2 RIO lamp/button bezel on the VDB heads + explode-view polish
Draw the cockpit RIO buttons around the mono-MFD and radar heads (explode
layout), lit by the host-commanded lamp state -- the display side of the
in-fork glass cockpit. Live-validated 2026-07-24 (operator).
- vpxlog.cpp: per-head button bezel in pal_draw, reading serialrio's new
RIO_GetPanelState seam. The 5 MFD heads get red buttons (4 top / 4 bottom,
100px tall tucked under a grown 640x500 display so a 10px lip shows); the
radar gets amber Secondary/Screen side columns (6x 104px each) plus a
centered bottom indicator strip (the 4 spares). Lamp byte decoded to
off/dim/bright (vRIO RioLampState, brighter of the two brightness fields);
a press shows white-hot. No labels -- the MFD shows each button's function.
Also swapped the two upper-outer MFD window NAMES to match their (already
position-swapped) desktop locations.
- serialrio.{cpp,h}: RIO_GetPanelState(lamps, pressed) accessor -- returns
false when no rio port, so non-rio configs and other heads render normally.
- pod-launch: in explode (dev) layout the Division bridge is a normal, freely
movable window -- not pinned topmost (Focus.cs) and nudged to 8,40 so its
title bar clears the top of the screen (its client was at 0,0, pushing the
frame off-screen). Cockpit/kiosk keeps the topmost + 0,0 borderless look.
Only affects the explode layout and only when a serial=rio port is present.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,16 +15,19 @@ namespace VwePod
|
||||
{
|
||||
internal static class Focus
|
||||
{
|
||||
public static string Apply(int x, int y)
|
||||
public static string Apply(int x, int y, bool pinRenderer)
|
||||
{
|
||||
var s = new StringBuilder();
|
||||
|
||||
// 1) renderer -> topmost
|
||||
// 1) renderer Z-order. Kiosk/cockpit: pin it always-on-top so a head
|
||||
// window never covers the out-the-window view. Explode (dev): leave
|
||||
// it a normal window so the operator can freely move/restack it.
|
||||
IntPtr r = FindRenderer();
|
||||
if (r != IntPtr.Zero)
|
||||
{
|
||||
SetWindowPos(r, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
s.Append("renderer topmost; ");
|
||||
SetWindowPos(r, pinRenderer ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
s.Append(pinRenderer ? "renderer topmost; " : "renderer movable; ");
|
||||
}
|
||||
else s.Append("renderer NOT found; ");
|
||||
|
||||
@@ -69,6 +72,7 @@ namespace VwePod
|
||||
|
||||
// ---- native ----
|
||||
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
|
||||
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
|
||||
private const uint SWP_NOSIZE = 0x0001, SWP_NOMOVE = 0x0002, SWP_NOZORDER = 0x0004;
|
||||
private const int SW_RESTORE = 9;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace VwePod
|
||||
var o = new Options();
|
||||
string modeName = null, confArg = null, rootArg = null, dosboxArg = null,
|
||||
bridgeScriptArg = null, rendererArg = null, aweArg = null;
|
||||
bool dosboxXySet = false;
|
||||
bool dosboxXySet = false, bridgePosSet = false;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ namespace VwePod
|
||||
case "--renderer": rendererArg = Next(a); break;
|
||||
case "--awe-rom": aweArg = Next(a); break;
|
||||
case "--layout": o.Layout = Next(a).Equals("explode", StringComparison.OrdinalIgnoreCase) ? LayoutMode.Explode : LayoutMode.Cockpit; break;
|
||||
case "--bridge-pos": o.BridgePos = Next(a); break;
|
||||
case "--bridge-pos": o.BridgePos = Next(a); bridgePosSet = true; break;
|
||||
case "--bridge-size": ParseWH(Next(a), out o.BridgeW, out o.BridgeH); break;
|
||||
case "--dosbox-xy": ParseWH(Next(a), out o.DosBoxX, out o.DosBoxY); dosboxXySet = true; break;
|
||||
case "--no-bridge": o.NoBridge = true; break;
|
||||
@@ -101,6 +101,12 @@ namespace VwePod
|
||||
// under the render window unless the caller placed it explicitly.
|
||||
if (!dosboxXySet && o.Mode.Name == "test") { o.DosBoxX = 900; o.DosBoxY = 600; }
|
||||
|
||||
// explode (dev) layout: the bridge is a normal framed window, but at
|
||||
// 0,0 SDL puts the CLIENT at 0,0 so the title bar sits off the top of
|
||||
// the screen (unmovable). Nudge it on-screen (frame needs y >= 31)
|
||||
// unless the caller placed it. Cockpit keeps 0,0 (kiosk, borderless-look).
|
||||
if (!bridgePosSet && o.Layout == LayoutMode.Explode) o.BridgePos = "8,40";
|
||||
|
||||
o.DosBox = dosboxArg ?? FirstExisting(
|
||||
Path.Combine(o.Root, "dosbox-x.exe"),
|
||||
Path.Combine(o.Root, "src", "src", "dosbox-x.exe"))
|
||||
|
||||
@@ -142,14 +142,16 @@ namespace VwePod
|
||||
// TerminateProcess skips this, but the job still closes with us.)
|
||||
Console.CancelKeyPress += (s, e) => { e.Cancel = false; job.Dispose(); };
|
||||
|
||||
// Window layout LAST so it wins over the child windows: renderer
|
||||
// -> always-on-top; DOSBox -> parked + foreground (keeps the emu
|
||||
// thread at foreground priority so the RIO ACK deadline isn't
|
||||
// missed). Give the windows a moment to exist first.
|
||||
// Window layout LAST so it wins over the child windows: DOSBox ->
|
||||
// parked + foreground (keeps the emu thread at foreground priority
|
||||
// so the RIO ACK deadline isn't missed). The renderer is pinned
|
||||
// topmost only in cockpit (kiosk) layout; in explode (dev) it stays
|
||||
// a normal, freely movable window. Give the windows a moment first.
|
||||
if (!opt.NoFocus)
|
||||
{
|
||||
Thread.Sleep(3000);
|
||||
Console.WriteLine("focus: " + Focus.Apply(opt.DosBoxX, opt.DosBoxY));
|
||||
Console.WriteLine("focus: " + Focus.Apply(
|
||||
opt.DosBoxX, opt.DosBoxY, opt.Layout == LayoutMode.Cockpit));
|
||||
}
|
||||
|
||||
// Authoritative for the whole session: block until DOSBox exits.
|
||||
|
||||
Reference in New Issue
Block a user