place the selection panel beside what it describes
This commit is contained in:
115
src/ui/SelectionBounds.cpp
Normal file
115
src/ui/SelectionBounds.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "SelectionBounds.h"
|
||||
|
||||
#include "Building.h"
|
||||
#include "DebrisComponent.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "FactoryQueries.h"
|
||||
#include "PositionComponent.h"
|
||||
#include "Simulation.h"
|
||||
#include "StationBodyComponent.h"
|
||||
#include "WorldCoordinates.h"
|
||||
#include "WorldPrimitives.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// The widget rectangle of a footprint anchored at a tile, both kinds of body being
|
||||
// described the same way.
|
||||
QRectF getFootprintWidgetRect(const WorldCoordinates& coordinates, QPoint anchor,
|
||||
QSize footprint)
|
||||
{
|
||||
const QPointF topLeft = coordinates.tileToWidget(anchor);
|
||||
return QRectF(topLeft.x(), topLeft.y(),
|
||||
footprint.width() * static_cast<qreal>(coordinates.getTilePx()),
|
||||
footprint.height() * static_cast<qreal>(coordinates.getTilePx()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
std::optional<QRectF> getBuildingWidgetRect(const FactoryState& state,
|
||||
const WorldCoordinates& coordinates,
|
||||
BuildingId id)
|
||||
{
|
||||
if (const Building* building = findBuilding(state, id))
|
||||
{
|
||||
return getFootprintWidgetRect(coordinates, building->anchor, building->footprint);
|
||||
}
|
||||
if (const ConstructionSite* site = findSite(state, id))
|
||||
{
|
||||
return getFootprintWidgetRect(coordinates, site->anchor, site->footprint);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<QRectF> getActorWidgetRect(EntityAdmin& admin,
|
||||
const WorldCoordinates& coordinates,
|
||||
entt::entity actor)
|
||||
{
|
||||
if (!admin.isValid(actor))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
if (admin.hasAll<StationBodyComponent>(actor))
|
||||
{
|
||||
const StationBodyComponent& body = admin.get<StationBodyComponent>(actor);
|
||||
return getFootprintWidgetRect(coordinates, body.anchor, body.footprint);
|
||||
}
|
||||
if (admin.hasAll<PositionComponent>(actor))
|
||||
{
|
||||
// A ship is a triangle about its center; the square its longest extent fits in
|
||||
// is what the panel is placed beside.
|
||||
const QPointF center =
|
||||
coordinates.worldToWidget(admin.get<PositionComponent>(actor).value);
|
||||
const qreal extent = static_cast<qreal>(getShipForwardExtentPx(coordinates));
|
||||
return QRectF(center.x() - extent, center.y() - extent,
|
||||
2.0 * extent, 2.0 * extent);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<QRectF> getDebrisWidgetRect(EntityAdmin& admin,
|
||||
const WorldCoordinates& coordinates,
|
||||
entt::entity debris)
|
||||
{
|
||||
if (!admin.isValid(debris) || !admin.hasAll<PositionComponent, DebrisComponent>(debris))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
const QPointF center =
|
||||
coordinates.worldToWidget(admin.get<PositionComponent>(debris).value);
|
||||
const qreal radius = static_cast<qreal>(getDebrisRadiusPx(coordinates));
|
||||
return QRectF(center.x() - radius, center.y() - radius, 2.0 * radius, 2.0 * radius);
|
||||
}
|
||||
|
||||
QRect getSelectionWidgetRect(Simulation& sim, const WorldCoordinates& coordinates,
|
||||
const std::vector<BuildingId>& buildings,
|
||||
const std::vector<entt::entity>& actors,
|
||||
const std::vector<entt::entity>& debris)
|
||||
{
|
||||
QRectF bounds;
|
||||
// A null rect unites to nothing of its own, so the first object found sets the box
|
||||
// and every later one grows it.
|
||||
auto add = [&bounds](const std::optional<QRectF>& rect)
|
||||
{
|
||||
if (rect.has_value())
|
||||
{
|
||||
bounds = bounds.isNull() ? *rect : bounds.united(*rect);
|
||||
}
|
||||
};
|
||||
|
||||
for (BuildingId id : buildings)
|
||||
{
|
||||
add(getBuildingWidgetRect(sim.getFactoryState(), coordinates, id));
|
||||
}
|
||||
for (entt::entity actor : actors)
|
||||
{
|
||||
add(getActorWidgetRect(sim.getAdmin(), coordinates, actor));
|
||||
}
|
||||
for (entt::entity piece : debris)
|
||||
{
|
||||
add(getDebrisWidgetRect(sim.getAdmin(), coordinates, piece));
|
||||
}
|
||||
|
||||
return bounds.isNull() ? QRect() : bounds.toAlignedRect();
|
||||
}
|
||||
Reference in New Issue
Block a user