From 7327343b2a5fe627b2878aa50f55c6e0823adf68 Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Tue, 18 Aug 2026 11:54:54 +0200 Subject: [PATCH] draw every modal the player meets while playing The dialogs were OS windows with a dim widget behind them, which is why a click beside one could not reach them: Qt drops mouse events for a window a modal blocks, so the dim -- a child of the game window -- never sees the press that REQ-UI-DIALOG-DISMISS now asks it to act on. REQ-UI-MODAL-CHROME states the rule the fix follows: a modal is drawn by the game on the dim, with no title bar, no window border, no window-manager close, and no way for the player to move it, resize it, or drag it off the window. Each draws its own header, as the blueprint selection dialog already does; content too large for the window scrolls inside the modal instead of hanging past the edge. The exception is failure reporting -- a config or blueprint file that will not load is still a system message box, since it must reach the player when there is nothing left to draw on. The requirements that described the old chrome follow: the blueprint dialog loses its window-manager close, the escape menu, game-over and win screens and both name dialogs say they are drawn, and REQ-UI-MODAL-DIM says the dim is the surface a modal sits on rather than a layer kept in step with it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x --- docs/requirements.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index f565855..1c97b86 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -109,7 +109,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro - REQ-HQ-BELT-INPUT: The HQ has a belt input port. Building blocks delivered to it are added to the global building blocks stock. - REQ-HQ-STATS: HQ stats (HP) are read from `stations.toml [hq]`. - REQ-HQ-STARTING-BLOCKS: At game start, the global building blocks stock is initialized to `world.toml [world].starting_building_blocks` (default 100). -- REQ-HQ-GAME-OVER: If the HQ is destroyed, the game ends. A game-over screen shows the final survival time and offers "Restart" and "Quit" buttons. +- REQ-HQ-GAME-OVER: If the HQ is destroyed, the game ends. A game-over screen, drawn by the game as every modal is (REQ-UI-MODAL-CHROME), shows the final survival time and offers "Restart" and "Quit" buttons. - REQ-HQ-INVULNERABLE: Factory buildings (other than the HQ) are never targeted or destroyed by enemies. ## Win Condition @@ -356,7 +356,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro - REQ-MOD-UI-BLUEPRINT-PANEL: The right column of the layout configuration dialog is the layout blueprint panel. It shows only blueprints whose `ship_type` matches the schematic of the shipyard for which the dialog was opened. The panel contains, from top to bottom: a "Create Blueprint" button, followed by a scrollable list of blueprint entries (one per matching blueprint, in creation order). -- REQ-MOD-UI-BLUEPRINT-CREATE: Clicking "Create Blueprint" opens a modal dialog prompting for a name. The dialog has Confirm and Cancel buttons. Clicking Cancel closes the dialog with no effect. Clicking Confirm with a non-empty name creates a blueprint from the module layout currently shown in the left-side layout grid (the in-progress state of the dialog, not the previously confirmed shipyard layout) and appends it to the blueprint list. +- REQ-MOD-UI-BLUEPRINT-CREATE: Clicking "Create Blueprint" opens a modal dialog prompting for a name, drawn by the game like every other modal (REQ-UI-MODAL-CHROME) and, like the other name dialog, dismissed by neither Q nor a click outside it (REQ-UI-DIALOG-DISMISS). The dialog has Confirm and Cancel buttons. Clicking Cancel closes the dialog with no effect. Clicking Confirm with a non-empty name creates a blueprint from the module layout currently shown in the left-side layout grid (the in-progress state of the dialog, not the previously confirmed shipyard layout) and appends it to the blueprint list. - REQ-MOD-UI-BLUEPRINT-ENTRY: Each blueprint entry shows the blueprint name and a delete icon ("×") to the right of the name. Clicking the entry (name area) loads that blueprint's module list into the left-side layout grid, replacing all currently placed modules. Module instances that are invalid for the current ship layout (unknown module type, locked module type, position outside the grid, position on a non-buildable cell, or overlapping another module in the same blueprint) are silently skipped; the remaining valid instances are placed. Clicking the delete icon ("×") removes that blueprint entry from the list immediately. @@ -485,11 +485,16 @@ The screen is a single column: a header bar across the top and the game world vi - **Presentation only.** Moving the panel is not a player command: it never enters the replay stream and has no effect on the simulation, consistent with the controls panel's collapsed state (REQ-UI-CONTROLS-PANEL). The desired position is not saved to disk. - REQ-UI-PANEL-MODAL: **A modal opened from the selection panel opens on the panel.** A modal the player opens from a control inside the selection panel is placed **centered on the panel's current rectangle** rather than centered on the game window, so it appears where the player is already looking and under the cursor that just clicked the control. This is the same reason the panel itself is placed beside the selection instead of at a fixed corner (REQ-UI-SELECTION-PANEL): a modal centered on the window sends the cursor back across the view and then back again. Two modals are opened from the panel — the recipe/schematic selection dialog (REQ-UI-SELECT-BUTTON), from the selection button; and the layout configuration dialog (REQ-MOD-UI-DIALOG), both from the "Configure" button (REQ-MOD-UI-PREVIEW) and when it opens automatically after a schematic change (REQ-MOD-UI-AUTO-DIALOG). - **The panel's rectangle as it currently stands.** The modal is centered on where the panel actually is when the modal opens: the position resolved from the anchor rectangle (REQ-UI-SELECTION-PANEL) or, once the player has dragged the panel, the position they dragged it to (REQ-UI-SELECTION-PANEL-DRAG). The panel is always shown when one of these modals opens, since the modal is opened from a control within it (REQ-UI-EMPTY-SELECTION). - - **Kept inside the game window.** Should the modal, centered that way, extend past an edge of the game window, it is pushed back inside; its size is never changed to make it fit. A modal larger than the window in a dimension is instead aligned with the window's top or left edge in that dimension, so the part read first stays visible. + - **Kept inside the game window.** Should the modal, centered that way, extend past an edge of the game window, it is pushed back inside. A modal that cannot fit the window in a dimension is aligned with the window's top or left edge in that dimension, so the part read first stays visible, and the content that does not fit is reached by scrolling within the modal rather than by the modal growing past the window (REQ-UI-MODAL-CHROME). - **Placement is all that changes.** The modal is modal as before, pauses the game and restores the speed on close as before (REQ-UI-SELECT-BUTTON, REQ-MOD-UI-DIALOG), shows the dim over the entire window including the panel it sits on (REQ-UI-MODAL-DIM), and is dismissed the same way. That it covers the panel costs nothing: while it is open the panel is dimmed and takes no input anyway — a click on the part of the panel the modal leaves uncovered is a click outside the modal and dismisses it, like any other click beyond its frame (REQ-UI-DIALOG-DISMISS). - **Only these modals.** Every other modal is placed as before, centered on the game window: the escape menu (REQ-UI-GAME-MENU), the blueprint save and selection dialogs (REQ-UI-BLUEPRINT-CREATE, REQ-UI-BLUEPRINT-DIALOG), and the schematic choice dialog (REQ-DEF-SCHEMATIC-DROP), none of which is opened from the panel. So is a modal opened from another modal rather than from the panel — the Create Blueprint name dialog within the layout configuration dialog (REQ-MOD-UI-BLUEPRINT-CREATE) — which is placed against the modal that opened it. - **Presentation only.** The placement is computed once, when the modal opens, and is not revisited while it is open; the panel cannot move meanwhile, being behind the modal and receiving no input. It is not a player command, never enters the replay stream, and has no effect on the simulation. -- REQ-UI-MODAL-DIM: While a modal dialog, menu, or full-screen state screen is open on top of the game, a transparent black overlay (a dim/scrim) is drawn over the **entire game window** — the header bar, the game world view, and the widgets floating over it (the build button bar, REQ-UI-BUILD-BAR, the selection panel, REQ-UI-SELECTION-PANEL, and the controls panel, REQ-UI-CONTROLS-PANEL) — behind that modal, so the game reads as inactive while the modal holds focus. The overlay is shown for every modal that auto-pauses the simulation — the escape menu (REQ-UI-GAME-MENU), the recipe/schematic selection dialog (REQ-UI-SELECT-BUTTON), the layout configuration dialog (REQ-MOD-UI-DIALOG), the schematic choice dialog (REQ-DEF-SCHEMATIC-DROP), the blueprint save dialog (REQ-UI-BLUEPRINT-CREATE), and the blueprint selection dialog (REQ-UI-BLUEPRINT-DIALOG) — as well as the game-over screen (REQ-HQ-GAME-OVER) and the win screen (REQ-WIN-SCREEN), which end rather than pause the game. When modals are nested (for example the Create Blueprint name dialog (REQ-MOD-UI-BLUEPRINT-CREATE) opened from the layout configuration dialog), only a single dim is shown over the game window; nested modals do not stack additional overlays. The same applies when one modal hands directly off to another — the blueprint save dialog opening the blueprint selection dialog on confirm (REQ-UI-BLUEPRINT-CREATE): the dim persists across the handoff rather than flickering off and back on, and the simulation is not resumed in between. The dim color and opacity are read from `visuals.toml [overlays]` (a semi-transparent black modal-dim color), consistent with the other overlay colors. The overlay is presentation-only and has no effect on the simulation. +- REQ-UI-MODAL-CHROME: **Every modal the player meets while playing is drawn by the game.** A modal is not an operating-system window: it has no title bar, no window border, and no window-manager close button, and the player can neither move it, resize it, nor drag it out of the game window. It is drawn inside the game window, on the dim that covers that window (REQ-UI-MODAL-DIM), which is the surface it sits on rather than a scrim behind a separate window. This holds for every one of them: the recipe/schematic selection dialog (REQ-UI-SELECT-BUTTON), the layout configuration dialog (REQ-MOD-UI-DIALOG), the blueprint save and selection dialogs (REQ-UI-BLUEPRINT-CREATE, REQ-UI-BLUEPRINT-DIALOG), the Create Blueprint name dialog (REQ-MOD-UI-BLUEPRINT-CREATE), the schematic choice dialog (REQ-DEF-SCHEMATIC-DROP), the escape menu (REQ-UI-GAME-MENU), and the game-over and win screens (REQ-HQ-GAME-OVER, REQ-WIN-SCREEN). One look for all of them, and one place the player's attention stays. + - **Each draws its own header.** Where a modal has a title it is a line the modal draws, as the blueprint selection dialog already draws `Blueprints` (REQ-UI-BLUEPRINT-DIALOG); where it has a close control it is a drawn button, as that dialog's `×` is. A modal without either shows neither — the schematic choice dialog has no way out but choosing (REQ-DEF-SCHEMATIC-DROP), and nothing about being a drawn modal gives it one. + - **It never leaves the window.** A modal is placed inside the game window (REQ-UI-PANEL-MODAL) and stays there. Content too large for the window **scrolls within the modal** rather than extending past the window's edge, so nothing is placed where the player cannot reach it. + - **The exception is failure reporting.** A failure that leaves nothing to draw on — a config file that fails to load at startup or on the reload a Restart performs (REQ-CFG-RELOAD), a blueprint file that cannot be read (REQ-UI-BLUEPRINT-LOAD) — is reported by a plain system message box instead. Such a message must reach the player when the game window is not in a state to host anything, so it cannot be built on the machinery whose failure it is reporting. + - **Presentation only.** How a modal is framed has no effect on the simulation and never enters the replay stream. +- REQ-UI-MODAL-DIM: While a modal dialog, menu, or full-screen state screen is open on top of the game, a transparent black overlay (a dim/scrim) is drawn over the **entire game window** — the header bar, the game world view, and the widgets floating over it (the build button bar, REQ-UI-BUILD-BAR, the selection panel, REQ-UI-SELECTION-PANEL, and the controls panel, REQ-UI-CONTROLS-PANEL) — behind that modal, so the game reads as inactive while the modal holds focus. The modal is drawn on that overlay rather than in a window of its own (REQ-UI-MODAL-CHROME), so the dim is the surface it sits on and not a separate layer that has to be kept in step with it. The overlay is shown for every modal that auto-pauses the simulation — the escape menu (REQ-UI-GAME-MENU), the recipe/schematic selection dialog (REQ-UI-SELECT-BUTTON), the layout configuration dialog (REQ-MOD-UI-DIALOG), the schematic choice dialog (REQ-DEF-SCHEMATIC-DROP), the blueprint save dialog (REQ-UI-BLUEPRINT-CREATE), and the blueprint selection dialog (REQ-UI-BLUEPRINT-DIALOG) — as well as the game-over screen (REQ-HQ-GAME-OVER) and the win screen (REQ-WIN-SCREEN), which end rather than pause the game. When modals are nested (for example the Create Blueprint name dialog (REQ-MOD-UI-BLUEPRINT-CREATE) opened from the layout configuration dialog), only a single dim is shown over the game window; nested modals do not stack additional overlays. The same applies when one modal hands directly off to another — the blueprint save dialog opening the blueprint selection dialog on confirm (REQ-UI-BLUEPRINT-CREATE): the dim persists across the handoff rather than flickering off and back on, and the simulation is not resumed in between. The dim color and opacity are read from `visuals.toml [overlays]` (a semi-transparent black modal-dim color), consistent with the other overlay colors. The overlay is presentation-only and has no effect on the simulation. - REQ-UI-DIALOG-DISMISS: **An open dialog is dismissed by Q or by a click outside it.** Either gesture does exactly what that dialog's own Cancel or close already does and nothing else, and both reach the same three dialogs. Q is the key that backs the player out in the game world (REQ-UI-HOTKEYS), doing the same on a dialog: a second key alongside Escape rather than a new behavior, so the player backs out of a dialog with the key their hand is already on. The click is the gesture that already puts a thing away by landing beside it — a click on empty world space clears the selection and with it the selection panel (REQ-UI-ENTITY-CLICK-SELECT, REQ-UI-EMPTY-SELECTION) — so a dialog is left the same way, by clicking away from it. The three dialogs that take both: - **The recipe/schematic selection dialog** (REQ-UI-SELECT-BUTTON) — closes with the current recipe or schematic unchanged. @@ -566,7 +571,7 @@ The screen is a single column: a header bar across the top and the game world vi ### Escape Menu -- REQ-UI-GAME-MENU: Pressing Escape at any time opens the escape menu as a modal dialog and pauses the simulation (sets speed to 0×). On close, the simulation speed is restored to what it was before the menu was opened — so if the game was already paused, it remains paused. The menu contains three buttons: +- REQ-UI-GAME-MENU: Pressing Escape at any time opens the escape menu as a modal dialog drawn by the game (REQ-UI-MODAL-CHROME) and pauses the simulation (sets speed to 0×). On close, the simulation speed is restored to what it was before the menu was opened — so if the game was already paused, it remains paused. The menu contains three buttons: - **Continue** — closes the menu and returns to the game. - **Restart** — resets the simulation to its initial state and closes the menu at 1× speed. - **Quit** — closes the application. @@ -751,14 +756,14 @@ The controls panel tells the player which controls are available right now. It i Blueprints occupy no permanent screen space. They are saved with **Ctrl+C** from the current selection (REQ-UI-BLUEPRINT-CREATE) and picked for placement from the blueprint selection dialog, opened with **Ctrl+V** (REQ-UI-BLUEPRINT-DIALOG). The unmodified **C** and **V** keys are the throwaway counterparts of the same two gestures: they capture and re-place a single unnamed temporary blueprint that is never saved and never listed (REQ-UI-BLUEPRINT-TEMP). Blueprints have no widget on the game screen at all. (The ship layout blueprint panel of the layout configuration dialog, REQ-MOD-UI-BLUEPRINT-PANEL, is a separate feature and is unaffected.) -- REQ-UI-BLUEPRINT-CREATE: Pressing **Ctrl+C** (REQ-UI-HOTKEYS) opens the modal **blueprint save dialog**, which pauses the simulation and dims the game window (REQ-UI-MODAL-DIM). It has effect only when at least one player-placeable building (i.e. a building with a button in the build button bar) is currently selected; non-player-placeable buildings (HQ, defence stations) in the selection do not count toward this condition, and pressing Ctrl+C with an empty selection or a selection of only non-player-placeable buildings does nothing (no dialog opens). A selected player-placeable building may be either an operational building or a construction site (a building placed but not yet fully built, REQ-BLD-SITE-CONFIG); both count toward this condition and are captured identically (REQ-UI-BLUEPRINT-STORAGE). The dialog prompts the player to enter a name and has Confirm and Cancel buttons. Clicking Cancel — or pressing Escape, or closing the dialog — closes it with no effect and does not open the blueprint selection dialog. Clicking Confirm with a non-empty name creates a blueprint from the current selection, silently excluding any non-player-placeable buildings, appends it to the blueprint list, closes the save dialog, and immediately opens the blueprint selection dialog (REQ-UI-BLUEPRINT-DIALOG) showing the new blueprint among the others. +- REQ-UI-BLUEPRINT-CREATE: Pressing **Ctrl+C** (REQ-UI-HOTKEYS) opens the modal **blueprint save dialog**, which pauses the simulation and dims the game window (REQ-UI-MODAL-DIM). It has effect only when at least one player-placeable building (i.e. a building with a button in the build button bar) is currently selected; non-player-placeable buildings (HQ, defence stations) in the selection do not count toward this condition, and pressing Ctrl+C with an empty selection or a selection of only non-player-placeable buildings does nothing (no dialog opens). A selected player-placeable building may be either an operational building or a construction site (a building placed but not yet fully built, REQ-BLD-SITE-CONFIG); both count toward this condition and are captured identically (REQ-UI-BLUEPRINT-STORAGE). The dialog is drawn by the game like every other modal (REQ-UI-MODAL-CHROME): it prompts the player to enter a name under its own title and has Confirm and Cancel buttons. Clicking Cancel — or pressing Escape — closes it with no effect and does not open the blueprint selection dialog. It is not dismissed by Q or by a click outside it, a half-typed name being work in progress (REQ-UI-DIALOG-DISMISS). Clicking Confirm with a non-empty name creates a blueprint from the current selection, silently excluding any non-player-placeable buildings, appends it to the blueprint list, closes the save dialog, and immediately opens the blueprint selection dialog (REQ-UI-BLUEPRINT-DIALOG) showing the new blueprint among the others. - REQ-UI-BLUEPRINT-DIALOG: The **blueprint selection dialog** is the only place saved blueprints are shown. It is opened by pressing **Ctrl+V** (REQ-UI-HOTKEYS) and by confirming a save (REQ-UI-BLUEPRINT-CREATE). It is modal, pauses the simulation, and dims the game window (REQ-UI-MODAL-DIM). The dialog has a fixed size and consists of: - - A **title bar** reading `Blueprints`, followed by a small dimmed **hotkey badge** reading `Ctrl+V` — the same "learn the shortcut from the widget" device as the build button badges (REQ-UI-BUILD-COST) — and, at the far right, a **close ("×") button**. + - A **title bar** the dialog draws itself (REQ-UI-MODAL-CHROME) reading `Blueprints`, followed by a small dimmed **hotkey badge** reading `Ctrl+V` — the same "learn the shortcut from the widget" device as the build button badges (REQ-UI-BUILD-COST) — and, at the far right, a **close ("×") button**. - Below it, a **scrollable two-column grid of blueprint cards** (REQ-UI-BLUEPRINT-CARD), one per saved blueprint, filling the grid left to right and top to bottom in creation order. The column count is fixed at two; the grid scrolls vertically when the cards do not fit, and does not scroll horizontally. - When no blueprints are saved, the dialog still opens and shows an empty-state message in place of the grid, telling the player that blueprints are created with Ctrl+C from a selection of buildings. - Clicking the close button, pressing Escape, pressing Q, clicking outside the dialog (REQ-UI-DIALOG-DISMISS), or closing the dialog through the window manager closes it with no other effect: the current selection, build mode, and blueprint list are unchanged, and the simulation speed is restored to what it was before the dialog was opened. While the dialog is open, Escape closes it rather than opening the escape menu (REQ-UI-GAME-MENU), and Q closes it rather than acting on the game world beneath — as does the click, which is spent on closing the dialog and does not reach what it landed on. + Clicking the close button, pressing Escape, pressing Q, or clicking outside the dialog (REQ-UI-DIALOG-DISMISS) closes it with no other effect: the current selection, build mode, and blueprint list are unchanged, and the simulation speed is restored to what it was before the dialog was opened. While the dialog is open, Escape closes it rather than opening the escape menu (REQ-UI-GAME-MENU), and Q closes it rather than acting on the game world beneath — as does the click, which is spent on closing the dialog and does not reach what it landed on. ``` +------------------------------------------------------+