give the escape menu and the name prompts the game's own frame
The last dialogs wearing system chrome were the three QMessageBoxes -- the escape menu, the game-over and win screens -- and the two QInputDialogs that name a blueprint. They are the ones the player meets at the sharpest moments of a run, and they looked like alerts from the operating system. MessageDialog and NameInputDialog replace them on the layer. The message dialog names its buttons by the index addButton hands back and reports which was clicked, with Escape standing for a button the caller nominates rather than for a dismissal of its own -- Continue in the escape menu, as it was explicitly set to before, and Quit on the two state screens, which is where the reject role sent it. Neither dialog takes Q or a click outside: every button is a decision, and a half-typed name is work in progress (REQ-UI-DIALOG-DISMISS). Two things the layer needed for the nested case: it now tracks the scroll area each modal is shown in, so a modal opened with no anchor centers on the one it was opened from rather than on the window -- which is where the Create Blueprint prompt belongs (REQ-UI-PANEL-MODAL) -- and findFor() walks a widget's parents to the layer, so the blueprint panel buried in the layout dialog can open a modal without every widget in between carrying a pointer. The three error boxes stay system dialogs on purpose: config load, config reload, and blueprint file load all report a failure that may leave nothing to draw on (REQ-UI-MODAL-CHROME). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
@@ -10,10 +10,7 @@
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -35,8 +32,10 @@
|
||||
#include "ShipLayoutDialog.h"
|
||||
#include "BuildingIconCache.h"
|
||||
#include "ItemIconCache.h"
|
||||
#include "MessageDialog.h"
|
||||
#include "ModalLayer.h"
|
||||
#include "ModalPauseScope.h"
|
||||
#include "NameInputDialog.h"
|
||||
#include "Simulation.h"
|
||||
#include "Tick.h"
|
||||
#include "VisualsLoader.h"
|
||||
@@ -257,17 +256,17 @@ void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*e
|
||||
{
|
||||
ModalPauseScope pause(*m_gameWorldView);
|
||||
|
||||
ModalLayerHold dim(*m_modalLayer);
|
||||
QMessageBox box(this);
|
||||
box.setWindowTitle(tr("Paused"));
|
||||
QPushButton* continueBtn = box.addButton(tr("Continue"), QMessageBox::AcceptRole);
|
||||
QPushButton* restartBtn = box.addButton(tr("Restart"), QMessageBox::ResetRole);
|
||||
QPushButton* quitBtn = box.addButton(tr("Quit"), QMessageBox::DestructiveRole);
|
||||
box.setEscapeButton(continueBtn);
|
||||
box.exec();
|
||||
MessageDialog box(tr("Paused"), QString(), m_modalLayer);
|
||||
const int continueIndex = box.addButton(tr("Continue"));
|
||||
const int restartIndex = box.addButton(tr("Restart"));
|
||||
const int quitIndex = box.addButton(tr("Quit"));
|
||||
// Escape stands for Continue, as it did when this was a system box
|
||||
// (REQ-UI-GAME-MENU).
|
||||
box.setEscapeButtonIndex(continueIndex);
|
||||
m_modalLayer->execute(box);
|
||||
|
||||
QAbstractButton* clicked = box.clickedButton();
|
||||
if (clicked == restartBtn)
|
||||
const std::optional<int> clicked = box.getClickedButtonIndex();
|
||||
if (clicked == restartIndex)
|
||||
{
|
||||
std::optional<GameConfig> newConfig = reloadConfig();
|
||||
if (!newConfig.has_value())
|
||||
@@ -285,7 +284,7 @@ void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*e
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<CommandRequestedEvent>(command));
|
||||
}
|
||||
else if (clicked == quitBtn)
|
||||
else if (clicked == quitIndex)
|
||||
{
|
||||
pause.release();
|
||||
close();
|
||||
@@ -476,14 +475,13 @@ void MainWindow::handleEvent(std::shared_ptr<const BlueprintSaveRequestedEvent>
|
||||
ModalPauseScope pause(*m_gameWorldView);
|
||||
ModalLayerHold dim(*m_modalLayer);
|
||||
|
||||
bool ok = false;
|
||||
const QString name = QInputDialog::getText(
|
||||
this, tr("Create Blueprint"), tr("Blueprint name:"), QLineEdit::Normal,
|
||||
QString(), &ok);
|
||||
NameInputDialog nameDialog(tr("Create Blueprint"), tr("Blueprint name:"),
|
||||
m_modalLayer);
|
||||
const int result = m_modalLayer->execute(nameDialog);
|
||||
// Cancel, Escape, or an empty name: no blueprint, and no selection dialog.
|
||||
if (!ok || name.trimmed().isEmpty()) { return; }
|
||||
if (result != QDialog::Accepted || nameDialog.getName().isEmpty()) { return; }
|
||||
|
||||
m_blueprintLibrary->saveSelectionAs(name.trimmed());
|
||||
m_blueprintLibrary->saveSelectionAs(nameDialog.getName());
|
||||
showBlueprintSelectionDialog();
|
||||
}
|
||||
|
||||
@@ -513,17 +511,18 @@ void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/)
|
||||
const int minutes = totalSeconds / 60;
|
||||
const int seconds = totalSeconds % 60;
|
||||
|
||||
ModalLayerHold dim(*m_modalLayer);
|
||||
QMessageBox box(this);
|
||||
box.setWindowTitle(tr("Game Over"));
|
||||
box.setText(tr("HQ destroyed!\nSurvival time: %1:%2")
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0')));
|
||||
QPushButton* restartBtn = box.addButton(tr("Restart"), QMessageBox::AcceptRole);
|
||||
box.addButton(tr("Quit"), QMessageBox::RejectRole);
|
||||
box.exec();
|
||||
MessageDialog box(tr("Game Over"),
|
||||
tr("HQ destroyed!\nSurvival time: %1:%2")
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0')),
|
||||
m_modalLayer);
|
||||
const int restartIndex = box.addButton(tr("Restart"));
|
||||
const int quitIndex = box.addButton(tr("Quit"));
|
||||
// Escape quits, which is where the system box's reject role sent it.
|
||||
box.setEscapeButtonIndex(quitIndex);
|
||||
m_modalLayer->execute(box);
|
||||
|
||||
if (box.clickedButton() == restartBtn)
|
||||
if (box.getClickedButtonIndex() == restartIndex)
|
||||
{
|
||||
std::optional<GameConfig> newConfig = reloadConfig();
|
||||
if (!newConfig.has_value())
|
||||
@@ -550,17 +549,18 @@ void MainWindow::handleEvent(std::shared_ptr<const WinEvent> /*event*/)
|
||||
const int minutes = totalSeconds / 60;
|
||||
const int seconds = totalSeconds % 60;
|
||||
|
||||
ModalLayerHold dim(*m_modalLayer);
|
||||
QMessageBox box(this);
|
||||
box.setWindowTitle(tr("Won!"));
|
||||
box.setText(tr("You collected all artifacts!\nSurvival time: %1:%2")
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0')));
|
||||
QPushButton* restartBtn = box.addButton(tr("Restart"), QMessageBox::AcceptRole);
|
||||
box.addButton(tr("Quit"), QMessageBox::RejectRole);
|
||||
box.exec();
|
||||
MessageDialog box(tr("Won!"),
|
||||
tr("You collected all artifacts!\nSurvival time: %1:%2")
|
||||
.arg(minutes, 2, 10, QChar('0'))
|
||||
.arg(seconds, 2, 10, QChar('0')),
|
||||
m_modalLayer);
|
||||
const int restartIndex = box.addButton(tr("Restart"));
|
||||
const int quitIndex = box.addButton(tr("Quit"));
|
||||
// Escape quits, which is where the system box's reject role sent it.
|
||||
box.setEscapeButtonIndex(quitIndex);
|
||||
m_modalLayer->execute(box);
|
||||
|
||||
if (box.clickedButton() == restartBtn)
|
||||
if (box.getClickedButtonIndex() == restartIndex)
|
||||
{
|
||||
std::optional<GameConfig> newConfig = reloadConfig();
|
||||
if (!newConfig.has_value())
|
||||
|
||||
Reference in New Issue
Block a user