The game window remembers where you put it too
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>
This commit is contained in:
+146
-51
@@ -18,10 +18,16 @@ namespace
|
||||
|
||||
const char layoutFileName[] = "mfd_layout.cfg";
|
||||
|
||||
// the panes that own a desktop window, so Save can walk them
|
||||
enum { maxLayoutPanes = 8 };
|
||||
MFDSplitView *layoutPanes[maxLayoutPanes];
|
||||
int layoutPaneCount = 0;
|
||||
// every window taking part, so Save can walk them
|
||||
enum { maxLayoutWindows = 12 };
|
||||
struct LayoutWindow
|
||||
{
|
||||
void *window;
|
||||
const char *title;
|
||||
Logical withSize;
|
||||
};
|
||||
LayoutWindow layoutWindows[maxLayoutWindows];
|
||||
int layoutWindowCount = 0;
|
||||
|
||||
int LayoutMode()
|
||||
{
|
||||
@@ -160,7 +166,7 @@ namespace
|
||||
// than trusting teardown, so a hard kill still leaves the
|
||||
// layout that was on screen. No-op unless the mode is save.
|
||||
//
|
||||
MFDSplitView_SaveLayout();
|
||||
RPWindowLayout_Save();
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
@@ -289,10 +295,11 @@ MFDSplitView::MFDSplitView(
|
||||
ShowWindow((HWND) window, SW_SHOWNOACTIVATE);
|
||||
|
||||
// only the exploded view's own windows can be dragged, so only
|
||||
// those have a position worth remembering
|
||||
if (ownWindow && layoutPaneCount < maxLayoutPanes)
|
||||
// those have a placement worth remembering. Position only - see
|
||||
// RPWindowLayout_Register.
|
||||
if (ownWindow)
|
||||
{
|
||||
layoutPanes[layoutPaneCount++] = this;
|
||||
RPWindowLayout_Register(window, paneTitle, False);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -306,15 +313,7 @@ MFDSplitView::~MFDSplitView()
|
||||
Check_Pointer(this);
|
||||
|
||||
// out of the layout registry before the window goes
|
||||
for (int i = 0; i < layoutPaneCount; ++i)
|
||||
{
|
||||
if (layoutPanes[i] == this)
|
||||
{
|
||||
layoutPanes[i] = layoutPanes[--layoutPaneCount];
|
||||
layoutPanes[layoutPaneCount] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RPWindowLayout_Forget(window);
|
||||
|
||||
if (window != NULL)
|
||||
{
|
||||
@@ -335,18 +334,61 @@ Logical
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Sticky placement: restore saved positions over the computed ones.
|
||||
//
|
||||
// Called after the exploded view has built and placed every pane, so a
|
||||
// pane the file does not mention simply keeps where the layout put it.
|
||||
// Position only - the saved size is read and discarded, because a pane's
|
||||
// size comes from its content and its button banks, and letting an old
|
||||
// w,h back in would misshape it after any geometry change.
|
||||
// Join the saved layout. Registering twice just refreshes the entry, so
|
||||
// a window re-registering after being rebuilt is harmless.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void
|
||||
MFDSplitView_LoadLayout()
|
||||
RPWindowLayout_Register(void *window, const char *title, Logical with_size)
|
||||
{
|
||||
if (LayoutMode() == LayoutOff || layoutPaneCount == 0)
|
||||
if (window == NULL || title == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < layoutWindowCount; ++i)
|
||||
{
|
||||
if (layoutWindows[i].window == window)
|
||||
{
|
||||
layoutWindows[i].title = title;
|
||||
layoutWindows[i].withSize = with_size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (layoutWindowCount >= maxLayoutWindows)
|
||||
{
|
||||
return;
|
||||
}
|
||||
layoutWindows[layoutWindowCount].window = window;
|
||||
layoutWindows[layoutWindowCount].title = title;
|
||||
layoutWindows[layoutWindowCount].withSize = with_size;
|
||||
++layoutWindowCount;
|
||||
}
|
||||
|
||||
void
|
||||
RPWindowLayout_Forget(void *window)
|
||||
{
|
||||
for (int i = 0; i < layoutWindowCount; ++i)
|
||||
{
|
||||
if (layoutWindows[i].window == window)
|
||||
{
|
||||
layoutWindows[i] = layoutWindows[--layoutWindowCount];
|
||||
layoutWindows[layoutWindowCount].window = NULL;
|
||||
layoutWindows[layoutWindowCount].title = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Sticky placement: restore the saved placement over the computed one.
|
||||
//
|
||||
// Called once everything has been built and placed, so a window the file
|
||||
// does not mention simply keeps where it was put. Size comes back only
|
||||
// for windows registered with it - see the header.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void
|
||||
RPWindowLayout_Load()
|
||||
{
|
||||
if (LayoutMode() == LayoutOff || layoutWindowCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -393,33 +435,75 @@ void
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < layoutPaneCount; ++i)
|
||||
for (int i = 0; i < layoutWindowCount; ++i)
|
||||
{
|
||||
MFDSplitView *pane = layoutPanes[i];
|
||||
if (pane != NULL && pane->Title() != NULL &&
|
||||
!strcmp(pane->Title(), cursor))
|
||||
LayoutWindow &entry = layoutWindows[i];
|
||||
if (entry.title == NULL || strcmp(entry.title, cursor) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
HWND target = (HWND) entry.window;
|
||||
if (target == NULL || !IsWindow(target))
|
||||
{
|
||||
pane->SetPosition(x, y);
|
||||
++restored;
|
||||
break;
|
||||
}
|
||||
|
||||
// a saved size of nothing is a corrupt line, not an instruction
|
||||
Logical size_it = (entry.withSize && w > 0 && h > 0) ? True : False;
|
||||
|
||||
//
|
||||
// Saved coordinates belong to whatever monitors were plugged
|
||||
// in that day. If the placement lands on none of today's, drop
|
||||
// it and keep the computed one - restoring the game window
|
||||
// somewhere invisible would leave nothing to drag back.
|
||||
//
|
||||
RECT landing;
|
||||
landing.left = x;
|
||||
landing.top = y;
|
||||
if (size_it)
|
||||
{
|
||||
landing.right = x + w;
|
||||
landing.bottom = y + h;
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT current;
|
||||
if (!GetWindowRect(target, ¤t))
|
||||
{
|
||||
break;
|
||||
}
|
||||
landing.right = x + (current.right - current.left);
|
||||
landing.bottom = y + (current.bottom - current.top);
|
||||
}
|
||||
if (MonitorFromRect(&landing, MONITOR_DEFAULTTONULL) == NULL)
|
||||
{
|
||||
DEBUG_STREAM << "MFDLayout: " << cursor << " was saved at "
|
||||
<< x << "," << y << " - off every monitor now, ignoring\n"
|
||||
<< std::flush;
|
||||
break;
|
||||
}
|
||||
|
||||
SetWindowPos(target, NULL, x, y, w, h,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE | (size_it ? 0 : SWP_NOSIZE));
|
||||
++restored;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
DEBUG_STREAM << "MFDLayout: restored " << restored << " pane position(s) from "
|
||||
DEBUG_STREAM << "MFDLayout: restored " << restored << " window placement(s) from "
|
||||
<< layoutFileName << "\n" << std::flush;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Write where every open pane currently is. The whole file each time - it
|
||||
// is a handful of lines, and a rewrite leaves nothing half-written for a
|
||||
// hard kill to catch.
|
||||
// Write where every registered window currently is. The whole file each
|
||||
// time - it is a handful of lines, and a rewrite leaves nothing
|
||||
// half-written for a hard kill to catch.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void
|
||||
MFDSplitView_SaveLayout()
|
||||
RPWindowLayout_Save()
|
||||
{
|
||||
if (LayoutMode() != LayoutSave || layoutPaneCount == 0)
|
||||
if (LayoutMode() != LayoutSave || layoutWindowCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -432,30 +516,41 @@ void
|
||||
return;
|
||||
}
|
||||
|
||||
fputs("# RP412 exploded-view pane placement. RP412MFDLAYOUT=save writes\n"
|
||||
"# this on each finished drag and on exit; =load restores it.\n"
|
||||
"# <title>=<x>,<y>,<w>,<h> - the size is written for reference and\n"
|
||||
"# ignored on load.\n", file);
|
||||
fputs("# RP412 window placement. RP412MFDLAYOUT=save writes this on each\n"
|
||||
"# finished drag and on exit; =load restores it.\n"
|
||||
"# <title>=<x>,<y>,<w>,<h>. The game window gets its size back too;\n"
|
||||
"# for the display panes the size is reference only, since theirs\n"
|
||||
"# follows their content.\n", file);
|
||||
|
||||
int wrote = 0;
|
||||
for (int i = 0; i < layoutPaneCount; ++i)
|
||||
for (int i = 0; i < layoutWindowCount; ++i)
|
||||
{
|
||||
MFDSplitView *pane = layoutPanes[i];
|
||||
if (pane == NULL || pane->Title() == NULL)
|
||||
LayoutWindow &entry = layoutWindows[i];
|
||||
if (entry.title == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
HWND pane_window = (HWND) pane->Window();
|
||||
if (pane_window == NULL || !IsWindow(pane_window))
|
||||
HWND entry_window = (HWND) entry.window;
|
||||
if (entry_window == NULL || !IsWindow(entry_window))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
RECT bounds;
|
||||
if (!GetWindowRect(pane_window, &bounds))
|
||||
//
|
||||
// rcNormalPosition rather than GetWindowRect: a minimised window
|
||||
// reports a nonsense rect and a maximised one reports the screen,
|
||||
// and neither is what to come back to. This is the restored
|
||||
// placement whatever state the window is in, so quitting from
|
||||
// maximised still records where the window will reappear.
|
||||
//
|
||||
WINDOWPLACEMENT placement;
|
||||
memset(&placement, 0, sizeof(placement));
|
||||
placement.length = sizeof(placement);
|
||||
if (!GetWindowPlacement(entry_window, &placement))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fprintf(file, "%s=%ld,%ld,%ld,%ld\n", pane->Title(),
|
||||
RECT bounds = placement.rcNormalPosition;
|
||||
fprintf(file, "%s=%ld,%ld,%ld,%ld\n", entry.title,
|
||||
(long) bounds.left, (long) bounds.top,
|
||||
(long) (bounds.right - bounds.left),
|
||||
(long) (bounds.bottom - bounds.top));
|
||||
@@ -463,7 +558,7 @@ void
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
DEBUG_STREAM << "MFDLayout: saved " << wrote << " pane position(s) to "
|
||||
DEBUG_STREAM << "MFDLayout: saved " << wrote << " window placement(s) to "
|
||||
<< layoutFileName << "\n" << std::flush;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user