,noframe takes the title bar away, and with it the only way out of the game. The console screen now offers its own, bottom left: half width and diagonally opposite LAUNCH GAME, because it is the one button on that screen you cannot undo and it should not sit next to the one everybody is aiming for. It goes through the same door as closing the window - fe.closed, so RPL4FrontEnd_Run returns False and the race loop breaks - rather than opening a second shutdown path. Two things had to move for it to make sense. The saved placement now loads in RPL4.CPP, right after the main window is shown, instead of only when SVGA16 builds the cockpit. That was not until a mission started, so the console screen came up at the default rect with its title bar still on and the window only jumped to the saved placement once a race began - which, for a flag whose whole purpose is to take the title bar off, meant it did nothing on the screen you land on. RPL4.CPP now owns the main window's registration outright and SVGA16's branches only reload; the reload after CockpitShellProc goes on still matters, since its WM_SIZE is what re-fits the canvas. That in turn made the exploded view's position-only registration incoherent - the startup load had already applied the size - so the game window is simply position and size everywhere now. The earlier reasoning that its exploded size IS the -res render size does not hold: the back buffer stretches to the window in either view, exactly as it does for the cockpit. WM_EXITSIZEMOVE moves from the cockpit subclass to RPL4.CPP's own WndProc, which the subclass chains to anyway. In its old home it only existed once a cockpit had been built, so dragging the window on the console screen - the obvious moment to put it where you want it - saved nothing. There is also a save on the way out of WinMain, for a session that never started a race and so never ran SVGA16's teardown save. Verified: on a bare-framed window the console screen comes up at the saved 1280x760 with client == window rect, EXIT GAME ends the process with code 0, and a screenshot shows it clear of the column content. A console-only session dragged to 333,222 900x640 wrote that on the drag, kept it through the exit, and came back to exactly it on relaunch - without a race anywhere in the round trip. The noframe and cockpit round trips still pass unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
233 lines
7.1 KiB
C++
233 lines
7.1 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, plus an optional ",noframe"
|
|
// that takes that window's title bar and border off - for a cockpit that
|
|
// fills a monitor edge to edge without -fit's all-or-nothing, or an
|
|
// exploded pane photographed without chrome. A bare window has nothing
|
|
// to drag by, so place it first and add the flag after; Save carries the
|
|
// flag back out, since it is an instruction rather than something
|
|
// measured off the window. Windows are always built framed, so deleting
|
|
// the flag is all it takes to get the frame back.
|
|
//
|
|
// 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. Nothing derives that size - -res
|
|
// only decides how sharp the scene is, and 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. RPL4.CPP registers it before the console
|
|
// screen, so the saved placement is there from the
|
|
// first frame rather than arriving when a race starts.
|
|
//
|
|
// 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();
|