clear the selection with Q, and drop it on entering a build mode

Implements the requirements committed in 731b887.

Q becomes a three-way branch in the action table, which is the layer that owns
what an input does: ExitMode while a mode is active, the new ClearSelection
while something is selected, EnterDeconstruct otherwise. The three partition
the situations between them, so resolution stays first-match-wins over
available actions and the handler never re-derives the precedence -- which is
why ClearSelection gets its own event rather than joining ModeCancel on Q.

GameWorldView clears the selection at each of the three events that enter a
mode; those are the only ways in, whichever button or key the player used. No
clear is needed where ModeCancel falls through to deconstruct mode: Q resolves
to ClearSelection while anything is selected, so there is nothing left by then.

The Selection context's Q row reads "Clear selection", sits last as the row
that hands the context back does everywhere, and carries the exit badge
styling -- one key that backs out should look the same wherever it appears.
Requirements follow that last point in REQ-UI-CONTROLS-CARD and
REQ-UI-CONTROLS-CONTENT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
2026-08-17 21:49:33 +02:00
parent 731b8874c9
commit b0fa0da813
11 changed files with 102 additions and 21 deletions

View File

@@ -1330,6 +1330,11 @@ void GameWorldView::selectInBox(bool additive)
if (!additive) { m_selection.clearAll(); }
}
void GameWorldView::clearSelectionForBuildMode()
{
m_selection.clearAll();
}
bool GameWorldView::isHoverLive() const
{
// underMouse() is false while the cursor sits on one of the floating panels,
@@ -1726,6 +1731,7 @@ void GameWorldView::handleEvent(std::shared_ptr<const BeamFiredEvent> event)
void GameWorldView::handleEvent(std::shared_ptr<const BuildingTypeSelectedEvent> event)
{
clearSelectionForBuildMode();
m_buildMode.enterBuilderMode(event->type);
// A mode entered by hotkey usually leaves the cursor exactly where it was, and no
// mouse move follows to place the ghost; entered from a build button it leaves the
@@ -1740,12 +1746,16 @@ void GameWorldView::handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEv
void GameWorldView::handleEvent(std::shared_ptr<const DeconstructModeToggleRequestedEvent> /*event*/)
{
clearSelectionForBuildMode();
m_buildMode.toggleDeconstructMode();
refreshHover();
}
void GameWorldView::handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event)
{
// The blueprint arrives already built from the selection this drops
// (REQ-UI-BLUEPRINT-TEMP, REQ-UI-SELECTION-EXCLUSIVE).
clearSelectionForBuildMode();
m_buildMode.enterBlueprintMode(event->blueprint);
refreshHover();
}
@@ -1790,14 +1800,19 @@ void GameWorldView::handleEvent(std::shared_ptr<const GhostRotationRequestedEven
void GameWorldView::handleEvent(std::shared_ptr<const ModeCancelRequestedEvent> /*event*/)
{
// One key backs out of whichever mode is active, and enters deconstruct mode
// when none is (REQ-UI-HOTKEYS).
// One key backs out of whichever mode is active, and enters deconstruct mode
// when none is (REQ-UI-HOTKEYS).
// One key backs out of whichever mode is active, and enters deconstruct mode when
// none is (REQ-UI-HOTKEYS). The selection case of that key never reaches here: it
// resolves to its own event, so there is nothing left to clear by the time the
// fallthrough enters deconstruct mode (REQ-UI-SELECTION-EXCLUSIVE).
if (m_buildMode.getMode() == BuildMode::None) { m_buildMode.toggleDeconstructMode(); }
else { m_buildMode.exitCurrentMode(); }
}
void GameWorldView::handleEvent(std::shared_ptr<const SelectionClearRequestedEvent> /*event*/)
{
m_selection.clearAll();
}
void GameWorldView::handleEvent(std::shared_ptr<const DebugDrawToggleRequestedEvent> /*event*/)
{
m_debugDraw = !m_debugDraw;