extract SelectionController
This commit is contained in:
@@ -46,7 +46,6 @@
|
||||
#include "ReplayRecorder.h"
|
||||
#include "DeconstructModeChangedEvent.h"
|
||||
#include "EntityHitTest.h"
|
||||
#include "EntitySelectionChangedEvent.h"
|
||||
#include "EventManager.h"
|
||||
#include "FacingComponent.h"
|
||||
#include "FactionComponent.h"
|
||||
@@ -58,7 +57,6 @@
|
||||
#include "PositionComponent.h"
|
||||
#include "RepairBehavior.h"
|
||||
#include "SalvageScrapBehavior.h"
|
||||
#include "DebrisSelectionChangedEvent.h"
|
||||
#include "DebrisSystem.h"
|
||||
#include "SelectionChangedEvent.h"
|
||||
#include "SensorRangeComponent.h"
|
||||
@@ -675,51 +673,35 @@ std::optional<QVector2D> GameWorldView::entityPosition(entt::entity entity) cons
|
||||
return m_sim->getAdmin().get<PositionComponent>(entity).value;
|
||||
}
|
||||
|
||||
void GameWorldView::clearDebrisSelection()
|
||||
{
|
||||
if (m_selectedDebris.empty()) { return; }
|
||||
m_selectedDebris.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DebrisSelectionChangedEvent>(m_selectedDebris));
|
||||
}
|
||||
|
||||
void GameWorldView::pruneDespawnedDebris()
|
||||
{
|
||||
if (m_selectedDebris.empty()) { return; }
|
||||
const std::vector<entt::entity>& selected = m_selection.getSelectedDebris();
|
||||
if (selected.empty()) { return; }
|
||||
|
||||
// Keeps the debris that still exist, in the order the simulation reports them.
|
||||
std::vector<entt::entity> live;
|
||||
for (const DebrisInfo& info : getAllDebrisInfo(m_sim->getAdmin()))
|
||||
{
|
||||
if (std::find(m_selectedDebris.begin(), m_selectedDebris.end(), info.entity)
|
||||
!= m_selectedDebris.end())
|
||||
if (std::find(selected.begin(), selected.end(), info.entity) != selected.end())
|
||||
{
|
||||
live.push_back(info.entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (live.size() != m_selectedDebris.size())
|
||||
if (live.size() != selected.size())
|
||||
{
|
||||
m_selectedDebris = std::move(live);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DebrisSelectionChangedEvent>(m_selectedDebris));
|
||||
m_selection.setSelectedDebris(std::move(live));
|
||||
}
|
||||
}
|
||||
|
||||
void GameWorldView::clearEntitySelection()
|
||||
{
|
||||
if (m_selectedEntities.empty()) { return; }
|
||||
m_selectedEntities.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EntitySelectionChangedEvent>(m_selectedEntities));
|
||||
}
|
||||
|
||||
void GameWorldView::pruneDespawnedActors()
|
||||
{
|
||||
if (m_selectedEntities.empty()) { return; }
|
||||
const std::vector<entt::entity>& selected = m_selection.getSelectedActors();
|
||||
if (selected.empty()) { return; }
|
||||
|
||||
EntityAdmin& admin = m_sim->getAdmin();
|
||||
std::vector<entt::entity> live;
|
||||
for (entt::entity e : m_selectedEntities)
|
||||
for (entt::entity e : selected)
|
||||
{
|
||||
if (admin.isValid(e) && admin.hasAll<HealthComponent>(e)
|
||||
&& admin.get<HealthComponent>(e).hp > 0.0f)
|
||||
@@ -728,18 +710,7 @@ void GameWorldView::pruneDespawnedActors()
|
||||
}
|
||||
}
|
||||
|
||||
if (live.size() != m_selectedEntities.size())
|
||||
{
|
||||
m_selectedEntities = std::move(live);
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EntitySelectionChangedEvent>(m_selectedEntities));
|
||||
}
|
||||
}
|
||||
|
||||
bool GameWorldView::isEntitySelected(entt::entity entity) const
|
||||
{
|
||||
return std::find(m_selectedEntities.begin(), m_selectedEntities.end(), entity)
|
||||
!= m_selectedEntities.end();
|
||||
m_selection.setSelectedActors(std::move(live));
|
||||
}
|
||||
|
||||
void GameWorldView::stepSpeed(int delta)
|
||||
@@ -1417,7 +1388,7 @@ void GameWorldView::drawSelectionHighlights(QPainter& painter,
|
||||
painter.setPen(QPen(m_visuals->overlays.selectedOutline, 2));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
|
||||
for (BuildingId selId : m_selectedBuildingIds)
|
||||
for (BuildingId selId : m_selection.getSelectedBuildings())
|
||||
{
|
||||
const std::optional<QRectF> rect = footprintWidgetRect(coordinates, selId);
|
||||
if (!rect.has_value()) { continue; }
|
||||
@@ -1427,14 +1398,13 @@ void GameWorldView::drawSelectionHighlights(QPainter& painter,
|
||||
|
||||
// A ring around each selected piece of debris, sitting just outside the debris's
|
||||
// rendered circle (radius getTilePx()*0.2, matching drawDebris) (REQ-UI-DEBRIS-CLICK-SELECT).
|
||||
if (!m_selectedDebris.empty())
|
||||
if (!m_selection.getSelectedDebris().empty())
|
||||
{
|
||||
const qreal outlineRadius =
|
||||
static_cast<qreal>(coordinates.getTilePx() * 0.2f) + 3.0;
|
||||
for (const DebrisInfo& debris : getAllDebrisInfo(m_sim->getAdmin()))
|
||||
{
|
||||
if (std::find(m_selectedDebris.begin(), m_selectedDebris.end(), debris.entity)
|
||||
== m_selectedDebris.end()) { continue; }
|
||||
if (!m_selection.isDebrisSelected(debris.entity)) { continue; }
|
||||
painter.drawEllipse(coordinates.worldToWidget(debris.position),
|
||||
outlineRadius, outlineRadius);
|
||||
}
|
||||
@@ -1622,7 +1592,7 @@ void GameWorldView::drawStations(QPainter& painter, const WorldCoordinates& coor
|
||||
// colored blue/red by the player/enemy fill it is drawn over.
|
||||
drawBuildingIcon(painter, coordinates, visType, bboxRect, bv.fill);
|
||||
|
||||
if (isEntitySelected(e))
|
||||
if (m_selection.isActorSelected(e))
|
||||
{
|
||||
painter.setPen(QPen(m_visuals->overlays.selectedOutline, 2));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
@@ -1670,7 +1640,7 @@ void GameWorldView::drawShips(QPainter& painter, const WorldCoordinates& coordin
|
||||
painter.setBrush(it->second.fill);
|
||||
painter.drawPolygon(tri);
|
||||
|
||||
if (isEntitySelected(e))
|
||||
if (m_selection.isActorSelected(e))
|
||||
{
|
||||
painter.setPen(QPen(m_visuals->overlays.selectedOutline, 2));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
@@ -1899,7 +1869,7 @@ void GameWorldView::drawBeams(QPainter& painter, const WorldCoordinates& coordin
|
||||
void GameWorldView::drawSelectedTunnelConnections(QPainter& painter,
|
||||
const WorldCoordinates& coordinates)
|
||||
{
|
||||
if (m_selectedBuildingIds.empty()) { return; }
|
||||
if (m_selection.getSelectedBuildings().empty()) { return; }
|
||||
|
||||
const TunnelTileMap tunnels = collectTunnelTiles();
|
||||
if (tunnels.empty()) { return; }
|
||||
@@ -1910,7 +1880,7 @@ void GameWorldView::drawSelectedTunnelConnections(QPainter& painter,
|
||||
// (or overlapping runs) is filled exactly once — filling a semi-transparent green
|
||||
// twice would darken it (REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
|
||||
std::set<QPoint, QPointCompare> highlightTiles;
|
||||
for (const BuildingId id : m_selectedBuildingIds)
|
||||
for (const BuildingId id : m_selection.getSelectedBuildings())
|
||||
{
|
||||
std::optional<QPoint> anchor;
|
||||
std::optional<BuildingType> type;
|
||||
@@ -2429,130 +2399,84 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
||||
}
|
||||
|
||||
const bool ctrl = (event->modifiers() & Qt::ControlModifier) != 0;
|
||||
const QVector2D worldPos = coordinates.widgetToWorld(event->pos());
|
||||
|
||||
// Point hit-test precedence: buildings win over actors, which win over debris
|
||||
// (REQ-UI-SELECTION-CATEGORIES).
|
||||
std::optional<BuildingId> buildingHit = buildingAtTile(tile);
|
||||
if (!buildingHit.has_value()) { buildingHit = siteAtTile(tile); }
|
||||
|
||||
if (buildingHit.has_value())
|
||||
// Only a click that hit nothing starts a box drag. Starting one on a hit
|
||||
// would re-resolve the same object as a 1x1 box on release and undo the
|
||||
// click: a Ctrl+click would toggle the building off, then straight back on.
|
||||
if (!selectAtPoint(tile, coordinates.widgetToWorld(event->pos()), ctrl))
|
||||
{
|
||||
const BuildingId id = *buildingHit;
|
||||
// A building selection is exclusive: it clears any field selection —
|
||||
// actors and debris — because buildings win (REQ-UI-SELECTION-CATEGORIES).
|
||||
clearEntitySelection();
|
||||
clearDebrisSelection();
|
||||
if (ctrl)
|
||||
{
|
||||
bool found = false;
|
||||
std::vector<BuildingId> newSel;
|
||||
for (BuildingId sel : m_selectedBuildingIds)
|
||||
{
|
||||
if (sel == id) { found = true; }
|
||||
else { newSel.push_back(sel); }
|
||||
}
|
||||
if (!found) { newSel.push_back(id); }
|
||||
m_selectedBuildingIds = newSel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectedBuildingIds = { id };
|
||||
}
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
return;
|
||||
// selectAtPoint has already cleared the selection unless Ctrl is
|
||||
// preserving it for an additive drag.
|
||||
m_boxSelecting = true;
|
||||
m_boxStartTile = tile;
|
||||
m_boxCurrentTile = tile;
|
||||
}
|
||||
|
||||
// Selecting a field object (actor or debris) clears any building selection but
|
||||
// lets actors and debris coexist (REQ-UI-SELECTION-CATEGORIES).
|
||||
const entt::entity actorHit = entityAtWorldPos(m_sim->getAdmin(), worldPos);
|
||||
if (actorHit != entt::null)
|
||||
{
|
||||
if (!m_selectedBuildingIds.empty())
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
if (ctrl)
|
||||
{
|
||||
// Toggle this actor within the field selection, leaving debris intact
|
||||
// (REQ-UI-ENTITY-CLICK-SELECT).
|
||||
bool found = false;
|
||||
std::vector<entt::entity> newSel;
|
||||
for (entt::entity sel : m_selectedEntities)
|
||||
{
|
||||
if (sel == actorHit) { found = true; }
|
||||
else { newSel.push_back(sel); }
|
||||
}
|
||||
if (!found) { newSel.push_back(actorHit); }
|
||||
m_selectedEntities = newSel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A plain click makes this actor the sole selection.
|
||||
m_selectedEntities = { actorHit };
|
||||
clearDebrisSelection();
|
||||
}
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EntitySelectionChangedEvent>(m_selectedEntities));
|
||||
return;
|
||||
}
|
||||
|
||||
if (const entt::entity debrisHit =
|
||||
debrisAtWorldPos(m_sim->getAdmin(), worldPos); debrisHit != entt::null)
|
||||
{
|
||||
if (!m_selectedBuildingIds.empty())
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
if (ctrl)
|
||||
{
|
||||
// Toggle this debris within the field selection, leaving actors intact
|
||||
// (REQ-UI-DEBRIS-MULTI-SELECT).
|
||||
bool found = false;
|
||||
std::vector<entt::entity> newSel;
|
||||
for (entt::entity sel : m_selectedDebris)
|
||||
{
|
||||
if (sel == debrisHit) { found = true; }
|
||||
else { newSel.push_back(sel); }
|
||||
}
|
||||
if (!found) { newSel.push_back(debrisHit); }
|
||||
m_selectedDebris = newSel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A plain click makes this debris the sole selection.
|
||||
m_selectedDebris = { debrisHit };
|
||||
clearEntitySelection();
|
||||
}
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DebrisSelectionChangedEvent>(m_selectedDebris));
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty space: a plain click clears the whole selection and starts a box drag;
|
||||
// Ctrl preserves the current selection for additive box-select.
|
||||
if (!ctrl)
|
||||
{
|
||||
if (!m_selectedBuildingIds.empty())
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
clearEntitySelection();
|
||||
clearDebrisSelection();
|
||||
}
|
||||
m_boxSelecting = true;
|
||||
m_boxStartTile = tile;
|
||||
m_boxCurrentTile = tile;
|
||||
}
|
||||
}
|
||||
|
||||
bool GameWorldView::selectAtPoint(QPoint tile, QVector2D worldPos, bool additive)
|
||||
{
|
||||
// Point hit-test precedence: buildings win over actors, which win over debris
|
||||
// (REQ-UI-SELECTION-CATEGORIES). What each hit then does to the existing
|
||||
// selection is the controller's business, not this method's.
|
||||
const SelectionMode mode = additive ? SelectionMode::Toggle : SelectionMode::Replace;
|
||||
|
||||
std::optional<BuildingId> buildingHit = buildingAtTile(tile);
|
||||
if (!buildingHit.has_value()) { buildingHit = siteAtTile(tile); }
|
||||
if (buildingHit.has_value())
|
||||
{
|
||||
m_selection.selectBuildings({*buildingHit}, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
const entt::entity actorHit = entityAtWorldPos(m_sim->getAdmin(), worldPos);
|
||||
if (actorHit != entt::null)
|
||||
{
|
||||
m_selection.selectFieldObjects({actorHit}, {}, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
const entt::entity debrisHit = debrisAtWorldPos(m_sim->getAdmin(), worldPos);
|
||||
if (debrisHit != entt::null)
|
||||
{
|
||||
m_selection.selectFieldObjects({}, {debrisHit}, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Empty space: a plain click clears the whole selection, Ctrl preserves it.
|
||||
if (!additive) { m_selection.clearAll(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameWorldView::selectInBox(bool additive)
|
||||
{
|
||||
// Same precedence as a point click, over everything the box covers
|
||||
// (REQ-UI-MULTI-SELECT, REQ-UI-DEBRIS-MULTI-SELECT). The only difference is the
|
||||
// mode: a Ctrl box adds and never deselects, where a Ctrl click toggles.
|
||||
const SelectionMode mode = additive ? SelectionMode::Add : SelectionMode::Replace;
|
||||
|
||||
const std::vector<BuildingId> boxIds =
|
||||
buildingsInBox(m_boxStartTile, m_boxCurrentTile);
|
||||
if (!boxIds.empty())
|
||||
{
|
||||
m_selection.selectBuildings(boxIds, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<entt::entity> boxActors =
|
||||
actorsInBox(m_sim->getAdmin(), m_boxStartTile, m_boxCurrentTile);
|
||||
const std::vector<entt::entity> boxDebris =
|
||||
debrisInBox(m_sim->getAdmin(), m_boxStartTile, m_boxCurrentTile);
|
||||
if (!boxActors.empty() || !boxDebris.empty())
|
||||
{
|
||||
m_selection.selectFieldObjects(boxActors, boxDebris, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty box: a plain (non-additive) drag clears the current selection.
|
||||
if (!additive) { m_selection.clearAll(); }
|
||||
}
|
||||
|
||||
void GameWorldView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
const WorldCoordinates coordinates = getCoordinates();
|
||||
@@ -2675,91 +2599,7 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
||||
return;
|
||||
}
|
||||
|
||||
const bool ctrl = (event->modifiers() & Qt::ControlModifier) != 0;
|
||||
|
||||
if (!boxIds.empty())
|
||||
{
|
||||
// A box covering any building selects buildings; field objects (actors and
|
||||
// debris) in the box are ignored — buildings win (REQ-UI-MULTI-SELECT).
|
||||
clearEntitySelection();
|
||||
clearDebrisSelection();
|
||||
if (!ctrl)
|
||||
{
|
||||
m_selectedBuildingIds = boxIds;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (BuildingId id : boxIds)
|
||||
{
|
||||
bool found = false;
|
||||
for (BuildingId sel : m_selectedBuildingIds)
|
||||
{
|
||||
if (sel == id) { found = true; break; }
|
||||
}
|
||||
if (!found) { m_selectedBuildingIds.push_back(id); }
|
||||
}
|
||||
}
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
return;
|
||||
}
|
||||
|
||||
// No buildings in the box: select the field objects it covers — ships, defence
|
||||
// stations, and debris together (REQ-UI-MULTI-SELECT, REQ-UI-DEBRIS-MULTI-SELECT).
|
||||
const std::vector<entt::entity> boxActors =
|
||||
actorsInBox(m_sim->getAdmin(), m_boxStartTile, m_boxCurrentTile);
|
||||
const std::vector<entt::entity> boxDebris =
|
||||
debrisInBox(m_sim->getAdmin(), m_boxStartTile, m_boxCurrentTile);
|
||||
if (!boxActors.empty() || !boxDebris.empty())
|
||||
{
|
||||
if (!m_selectedBuildingIds.empty())
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
}
|
||||
if (!ctrl)
|
||||
{
|
||||
m_selectedEntities = boxActors;
|
||||
m_selectedDebris = boxDebris;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (entt::entity e : boxActors)
|
||||
{
|
||||
bool found = false;
|
||||
for (entt::entity sel : m_selectedEntities)
|
||||
{
|
||||
if (sel == e) { found = true; break; }
|
||||
}
|
||||
if (!found) { m_selectedEntities.push_back(e); }
|
||||
}
|
||||
for (entt::entity e : boxDebris)
|
||||
{
|
||||
bool found = false;
|
||||
for (entt::entity sel : m_selectedDebris)
|
||||
{
|
||||
if (sel == e) { found = true; break; }
|
||||
}
|
||||
if (!found) { m_selectedDebris.push_back(e); }
|
||||
}
|
||||
}
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<EntitySelectionChangedEvent>(m_selectedEntities));
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DebrisSelectionChangedEvent>(m_selectedDebris));
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty box: a plain (non-additive) drag clears the current selection.
|
||||
if (!ctrl)
|
||||
{
|
||||
m_selectedBuildingIds.clear();
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
|
||||
clearEntitySelection();
|
||||
clearDebrisSelection();
|
||||
}
|
||||
selectInBox((event->modifiers() & Qt::ControlModifier) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2978,9 +2818,7 @@ void GameWorldView::resetForNewGame()
|
||||
m_deconstructHoverBuildingId = std::nullopt;
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<DeconstructModeChangedEvent>(false));
|
||||
m_selectedBuildingIds.clear();
|
||||
clearEntitySelection();
|
||||
clearDebrisSelection();
|
||||
m_selection.clearAll();
|
||||
m_copiedConfig = std::nullopt;
|
||||
m_copyConfigFlashes.clear();
|
||||
m_boxSelecting = false;
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "EntitySelectionChangedEvent.h"
|
||||
#include "GameConfig.h"
|
||||
#include "Rotation.h"
|
||||
#include "SelectionController.h"
|
||||
#include "Tick.h"
|
||||
#include "TickDriver.h"
|
||||
#include "TunnelCompletion.h"
|
||||
@@ -247,21 +248,18 @@ private:
|
||||
void placeBlueprintAtTile(QPoint center);
|
||||
|
||||
std::optional<QVector2D> entityPosition(entt::entity entity) const;
|
||||
// Clears the debris selection, emitting an empty DebrisSelectionChangedEvent when
|
||||
// it was non-empty (REQ-UI-DEBRIS-CLICK-SELECT). Used when another selection
|
||||
// category takes over.
|
||||
void clearDebrisSelection();
|
||||
// Drops despawned or fully-collected debris from the selection and re-emits
|
||||
// when it changed (REQ-UI-DEBRIS-CLICK-SELECT). Called each frame from onFrame().
|
||||
// Drops despawned or fully-collected debris from the selection
|
||||
// (REQ-UI-DEBRIS-CLICK-SELECT). Called each frame from onFrame().
|
||||
void pruneDespawnedDebris();
|
||||
// Clears the actor selection, emitting an empty EntitySelectionChangedEvent when it was
|
||||
// non-empty (REQ-UI-ENTITY-CLICK-SELECT). Used when buildings take over.
|
||||
void clearEntitySelection();
|
||||
// Drops despawned or dead actors from the selection and re-emits when it changed
|
||||
// (REQ-UI-ENTITY-CLICK-SELECT). Called each frame from onFrame().
|
||||
// Drops despawned or dead actors from the selection (REQ-UI-ENTITY-CLICK-SELECT).
|
||||
// Called each frame from onFrame().
|
||||
void pruneDespawnedActors();
|
||||
// True if the given actor is part of the current actor selection.
|
||||
bool isEntitySelected(entt::entity entity) const;
|
||||
// Resolves a click into the selection it should produce, applying the category
|
||||
// precedence of REQ-UI-SELECTION-CATEGORIES; the controller owns what that then
|
||||
// does to the existing selection. Returns false when the click hit nothing,
|
||||
// which is the only case that goes on to start a box drag.
|
||||
bool selectAtPoint(QPoint tile, QVector2D worldPos, bool additive);
|
||||
void selectInBox(bool additive);
|
||||
void stepSpeed(int delta);
|
||||
void placeAtTile(QPoint tile);
|
||||
|
||||
@@ -410,9 +408,10 @@ private:
|
||||
std::optional<BuildingId> m_deconstructHoverBuildingId;
|
||||
bool m_debugDraw;
|
||||
|
||||
std::vector<BuildingId> m_selectedBuildingIds;
|
||||
std::vector<entt::entity> m_selectedEntities;
|
||||
std::vector<entt::entity> m_selectedDebris;
|
||||
// Owns the selection across all three categories and the rules for moving
|
||||
// between them (REQ-UI-SELECTION-CATEGORIES), including publishing the change
|
||||
// events. This widget only resolves what was hit.
|
||||
SelectionController m_selection;
|
||||
bool m_boxSelecting;
|
||||
QPoint m_boxStartTile;
|
||||
QPoint m_boxCurrentTile;
|
||||
|
||||
Reference in New Issue
Block a user