Files
dota_factory/src/ui/InputMapper.h
Malte Langkabel 57ab63202f float the build buttons as a bar over the game world
Implements the REQ-UI-BUILD-BAR rewrite: the build buttons leave the side
panel column for a widget floating at the bottom center of the game world
view, as one non-wrapping row. BuildButtonGrid is renamed BuildButtonBar and
its QGridLayout becomes a QHBoxLayout; the side panel column is left with two
equal-height panels.

Buttons become icon-only. Each face is composed into a single pixmap per
QIcon mode - hotkey badge in the top-left corner, chip icon centered, cost
and block icon below - because a QPushButton holds only one icon. That
replaces the custom-painted BuildButton and lets Qt grey an unaffordable
button by swapping the pixmap. The building name moves into the tooltip,
which now always leads with it, and a missing chip SVG falls back to the name
in the chip's place.

The badge labels come from InputMapper, searched out of the same table the
key handler uses so a badge cannot claim a key that does nothing. The
Deconstruct button has no cost, so it shows its name there instead, and sits
last behind a gap.

Parenting the bar to MainWindow makes creation order the stacking order: it
lands above the world view and its vignettes and below the modal dim, and Qt
routes mouse events to it rather than the world, which is the whole input
clause of REQ-UI-BUILD-BAR at no cost.

Requirements are amended for the two things the mockup added: the hotkey
badge and the Deconstruct caption.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
2026-08-06 08:12:38 +02:00

54 lines
2.1 KiB
C++

#pragma once
#include <QString>
#include "BuildingType.h"
#include "WorldCamera.h"
class QKeyEvent;
// Turns raw key events into the game's semantic actions and publishes them
// (REQ-UI-HOTKEYS). Widgets react to the action, never to the key, so the two can
// be rebound independently later; the bindings themselves are still hard-coded
// here for now.
//
// Two output shapes, chosen by the nature of the action rather than by taste:
//
// * Discrete actions — one press, one thing happens — fire an event as they
// always have.
// * Continuous actions, currently just panning, are held state. They also travel
// as events, but level-triggered ones carrying the complete current value (see
// PanDirectionChangedEvent), so a receiver never has to reconstruct state from
// edges.
//
// Holding the state here rather than in the widgets is what makes releaseAll()
// possible: one call clears every held action at once, which is how a lost key-up
// (focus moving to a modal mid-pan) stops being a stuck input.
class InputMapper
{
public:
// The build hotkey that selects the given building type, spelled for display on
// its build button's badge (REQ-UI-BUILD-COST): "1" for a plain digit, "⇧1" for
// a Shift+digit, and an empty string for a building type with no build hotkey.
// Lives here so the badge and the key handling read the same binding table.
static QString getBuildHotkeyLabel(BuildingType type);
// Both return true when the key was consumed; the caller passes anything else
// on to its base class so unrelated shortcuts keep working.
bool handleKeyPress(QKeyEvent* event);
bool handleKeyRelease(QKeyEvent* event);
// Drops all held-key state, publishing the resulting change. Call when the
// receiving widget can no longer expect key-up events.
void releaseAll();
private:
// Recomputes the pan direction from the held keys and publishes it if it
// changed. Holding both keys cancels out.
void updatePanDirection();
bool m_panLeftHeld = false;
bool m_panRightHeld = false;
PanDirection m_panDirection = PanDirection::None;
};