RP412MFDLAYOUT already kept the exploded view's display panes where they
were dragged. The main window is the one people move most, and it was
still being placed fresh every launch, so it joins them.
MFDSplitView_LoadLayout/SaveLayout become RPWindowLayout_Load/Save, with
Register/Forget taking any HWND rather than the module reaching into a
pane registry. Same file, same format, one more line in it.
What comes back depends on the window, so Register takes it as a flag:
display panes position only, as before. A pane's size follows its
content and its button banks, so an old size from a
different build must not distort it.
the game window position and size in the cockpit view. Nothing
derives that size - the cockpit fits itself to
whatever client area it is given - so a window sized
to suit a monitor should come back that way, and
half-restoring it would be the strange behaviour. In
the exploded view its size IS the render resolution
-res asked for, so there only the position returns.
Registered after the CockpitShellProc subclass is installed, on purpose:
the restore's WM_SIZE then runs LayoutCockpit again and the canvas
re-fits the restored client area. -fit does not register at all - it
owns the whole monitor, so there is no placement of the player's to
keep.
CockpitShellProc gained the WM_EXITSIZEMOVE hook the panes already had,
so dragging or resizing the shell writes the file immediately rather
than waiting for teardown.
Two hazards the panes were small enough to get away with and the game
window is not:
- Save reads rcNormalPosition rather than GetWindowRect. A minimised
window reports a nonsense rect and a maximised one reports the
screen; since the file is rewritten whole, either would have
replaced a good line with a useless one. rcNormalPosition is the
restored placement whatever state the window is in.
- Load drops any placement that intersects none of the monitors
currently plugged in. Restoring the game window onto a display that
is no longer there would leave nothing to drag back.
Verified by round trip in both views. Cockpit: dragged and resized to
240,120 1000x620, the file took it, a fresh launch in load mode came up
exactly there with a 984x581 client - and a screenshot confirms the
canvas re-fit it, displays at the corners and the map centred at the
bottom, nothing spilling. Exploded: the shell came back at 60,60 still
1280x720 from -res while Map came back at 777,333, which is the
size-flag split doing its job.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
225 lines
6.6 KiB
C++
225 lines
6.6 KiB
C++
#pragma once
|
|
|
|
#include "..\munga\style.h"
|
|
|
|
//########################################################################
|
|
//############################ MFDSplitView ##############################
|
|
//########################################################################
|
|
//
|
|
// One desktop window showing a single cockpit display, used by SVGA16's
|
|
// split mode (L4MFDSPLIT=1). The pod hardware packed the five monochrome
|
|
// MFDs into the color channels of two video outputs and mounted the map
|
|
// display rotated; on a desktop each display gets its own window instead.
|
|
//
|
|
// Each window also carries its display's physical button bank, exactly
|
|
// as mounted in the pod (geometry per vRIO's CockpitLayout):
|
|
// - MFDs: a 4x2 cluster - 4 red buttons above the glass, 4 below,
|
|
// RIO addresses descending from the cluster anchor (top-left = hi).
|
|
// - The map ("secondary screen"): 6 amber buttons down each side -
|
|
// Secondary 0x10-0x15 on the left, Screen 0x18-0x1D on the right
|
|
// (the remaining column addresses are Tesla relays, not buttons).
|
|
// Buttons light from the lamp state the game commands (via PadRIO) and
|
|
// press/release RIO units with the mouse.
|
|
//
|
|
// SVGA16 fills Pixels() (32bpp top-down, sourceWidth x sourceHeight as
|
|
// passed - already swapped by the caller for the rotated map) and calls
|
|
// Repaint(). Closing a view window just hides it.
|
|
//
|
|
class MFDSplitView
|
|
{
|
|
public:
|
|
enum ButtonStyle
|
|
{
|
|
NoButtons = 0,
|
|
MFDStrips, // 4 above + 4 below, addresses descend from anchorA
|
|
SideColumns // 6 per side; anchorA = left base, anchorB = right base
|
|
};
|
|
|
|
// With a parent, the view is created as a chrome-less child window
|
|
// inside the single cockpit window (x/y in parent client coords);
|
|
// without one it is its own draggable desktop window.
|
|
MFDSplitView(
|
|
const char *title,
|
|
int source_width,
|
|
int source_height,
|
|
int display_width,
|
|
int display_height,
|
|
int x,
|
|
int y,
|
|
ButtonStyle button_style = NoButtons,
|
|
int anchorA = 0,
|
|
int anchorB = 0,
|
|
void *parent = 0
|
|
);
|
|
|
|
int
|
|
ClientWidth() const
|
|
{ return clientWidth; }
|
|
int
|
|
ClientHeight() const
|
|
{ return clientHeight; }
|
|
|
|
// Move the pane (child mode: parent client coords). Panes overlap
|
|
// the viewscreen like the pod's bezels, so exact placement happens
|
|
// after construction from the measured client sizes.
|
|
void
|
|
SetPosition(int x, int y);
|
|
|
|
// Re-scale the glass (cockpit resized): the source buffer is
|
|
// unchanged, only the destination size and the button geometry
|
|
// derived from it.
|
|
void
|
|
Resize(int display_width, int display_height);
|
|
|
|
// Take the pane off screen. Used for the Winners Circle, which wants
|
|
// the whole viewscreen: the panes overlap it like the pod's bezels,
|
|
// so hiding them uncovers the full canvas underneath.
|
|
void
|
|
Hide();
|
|
|
|
// caption and HWND, for the sticky-placement file
|
|
const char *
|
|
Title() const
|
|
{ return paneTitle; }
|
|
void *
|
|
Window()
|
|
{ return window; }
|
|
|
|
~MFDSplitView();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
unsigned long *
|
|
Pixels()
|
|
{ return pixels; }
|
|
|
|
void
|
|
Repaint();
|
|
|
|
// Window-procedure callbacks (public for the registered WndProc)
|
|
void
|
|
Paint();
|
|
void
|
|
MouseDown(int x, int y);
|
|
void
|
|
MouseUp();
|
|
|
|
protected:
|
|
void
|
|
LayoutButtons(
|
|
ButtonStyle button_style,
|
|
int anchorA,
|
|
int anchorB,
|
|
int display_width,
|
|
int display_height,
|
|
int *client_width,
|
|
int *client_height
|
|
);
|
|
|
|
struct ScreenButton
|
|
{
|
|
int unit;
|
|
int x, y, w, h;
|
|
int amber; // 0 = red family, 1 = amber family
|
|
};
|
|
|
|
enum { maxButtons = 20 };
|
|
|
|
void
|
|
*window; // HWND
|
|
void
|
|
*blitHeader; // BITMAPINFOHEADER for StretchDIBits
|
|
unsigned long
|
|
*pixels;
|
|
int
|
|
sourceWidth,
|
|
sourceHeight;
|
|
|
|
int
|
|
displayX, displayY,
|
|
displayW, displayH;
|
|
int
|
|
clientWidth, clientHeight;
|
|
|
|
ScreenButton
|
|
buttons[maxButtons];
|
|
int
|
|
buttonCount;
|
|
int
|
|
pressedIndex;
|
|
|
|
// kept so the bank can be rebuilt when the cockpit re-scales
|
|
ButtonStyle
|
|
buttonStyle;
|
|
int
|
|
buttonAnchorA,
|
|
buttonAnchorB;
|
|
|
|
// the window caption, and the key this pane is saved under
|
|
const char
|
|
*paneTitle;
|
|
// True for a pane of its own on the desktop (the exploded view); the
|
|
// composited cockpit's panes are chrome-less children and cannot be
|
|
// dragged, so there is nothing to remember for them.
|
|
Logical
|
|
ownWindow;
|
|
};
|
|
|
|
//########################################################################
|
|
// Sticky window placement.
|
|
//
|
|
// The game window and, in the exploded view, each display pane are all
|
|
// draggable, but their placement is recomputed on every launch - so
|
|
// putting a window somewhere useful never survived the menu-race-menu
|
|
// loop. RP412MFDLAYOUT remembers it, in mfd_layout.cfg beside
|
|
// bindings.txt:
|
|
//
|
|
// off / 0 / unset computed placement only, no file (default)
|
|
// load / restore restore saved placement at startup, never write
|
|
// save / adjust restore, then rewrite on each finished drag and
|
|
// on teardown - the round trip
|
|
//
|
|
// One "<title>=x,y,w,h" line per window.
|
|
//
|
|
// Whether the size comes back depends on the window, which is why
|
|
// Register takes it as a flag:
|
|
//
|
|
// display panes position only. A pane's size follows its content and
|
|
// its button banks, so an old size from a different
|
|
// build must not distort it.
|
|
// the game window position, and size in the cockpit view. Nothing
|
|
// derives that size - the cockpit fits itself to
|
|
// whatever client area it is given - so a window sized
|
|
// to suit a monitor should come back that way, and
|
|
// half-restoring it would be the strange behaviour. In
|
|
// the exploded view its size IS the render resolution
|
|
// -res asked for, so there only the position returns.
|
|
//
|
|
// A placement that lands on none of the monitors currently plugged in is
|
|
// ignored rather than applied - restoring the game window off screen
|
|
// would leave nothing to drag back.
|
|
//
|
|
// Lives here because the display panes were the first to need it; the
|
|
// game window joined later rather than grow a second copy of the same
|
|
// file format.
|
|
//
|
|
// Ported from BT411's BT_GLASS_LAYOUT.
|
|
//########################################################################
|
|
|
|
// Take part in the saved layout. title is the key in the file and must
|
|
// outlive the window (the callers pass string literals).
|
|
void
|
|
RPWindowLayout_Register(void *window, const char *title, Logical with_size);
|
|
void
|
|
RPWindowLayout_Forget(void *window);
|
|
|
|
// Apply the saved placement over the computed one. Call once everything
|
|
// has been built and placed.
|
|
void
|
|
RPWindowLayout_Load();
|
|
|
|
// Write every registered window's placement. No-op unless mode is save.
|
|
void
|
|
RPWindowLayout_Save();
|