diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 8984339..24c6231 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -895,25 +895,31 @@ void GameWorldView::placeAtTile(QPoint tile) // Port glyph helper // --------------------------------------------------------------------------- -void GameWorldView::drawPortGlyph(QPainter& painter, QPoint bodyTile, - Rotation direction, const QColor& color) +void GameWorldView::drawPortGlyph(QPainter& painter, QPoint tile, + Rotation direction, const QColor& color, + bool centered) { const float px = getTilePx(); - const QRectF tr = tileRect(bodyTile); + const QRectF tr = tileRect(tile); const QPointF center(tr.x() + static_cast(px) * 0.5, tr.y() + static_cast(px) * 0.5); - QPointF offset; + QPointF edgeOffset; const char* ch; switch (direction) { - case Rotation::East: offset = QPointF(px * 0.25f, 0); ch = ">"; break; - case Rotation::West: offset = QPointF(-px * 0.25f, 0); ch = "<"; break; - case Rotation::North: offset = QPointF(0, -px * 0.25f); ch = "^"; break; - case Rotation::South: offset = QPointF(0, px * 0.25f); ch = "v"; break; + case Rotation::East: edgeOffset = QPointF(px * 0.25f, 0); ch = ">"; break; + case Rotation::West: edgeOffset = QPointF(-px * 0.25f, 0); ch = "<"; break; + case Rotation::North: edgeOffset = QPointF(0, -px * 0.25f); ch = "^"; break; + case Rotation::South: edgeOffset = QPointF(0, px * 0.25f); ch = "v"; break; default: return; } + // Centered glyphs sit in the middle of the tile (used for a port's target + // cell, REQ-UI-PORT-TARGET-GLYPH); otherwise offset toward the exit edge of + // the port's body tile (REQ-UI-PORT-GLYPH). + const QPointF offset = centered ? QPointF(0.0, 0.0) : edgeOffset; + const qreal half = static_cast(px) * 0.3; const QPointF pos = center + offset; const QRectF textRect(pos.x() - half, pos.y() - half, half * 2.0, half * 2.0); @@ -991,7 +997,7 @@ void GameWorldView::drawBuildings(QPainter& painter) for (const Port& port : b.outputPorts) { drawPortGlyph(painter, portBodyTile(port.tile, port.direction), - port.direction, bv.outline); + port.direction, bv.outline, /*centered*/ false); } // HP bar below the HQ footprint; the HQ's HP lives on its proxy entity. @@ -1070,7 +1076,8 @@ void GameWorldView::drawBuildings(QPainter& painter) { const QPoint absBody = s.anchor + portBodyTile(port.tile, port.direction); - drawPortGlyph(painter, absBody, port.direction, bv.outline); + drawPortGlyph(painter, absBody, port.direction, bv.outline, + /*centered*/ false); } } } @@ -1571,7 +1578,8 @@ void GameWorldView::drawOverlays(QPainter& painter) if (m_builderType.has_value()) { drawBuildingGhost(painter, *m_builderType, m_ghostTile, - m_ghostRotation, m_ghostValid); + m_ghostRotation, m_ghostValid, + /*showPortTargetGlyphs*/ true); } // Blueprint placement ghost @@ -1581,7 +1589,8 @@ void GameWorldView::drawOverlays(QPainter& painter) { const QPoint anchor = m_blueprintGhostTile + bb.offset; const bool valid = isValidPlacement(bb.type, anchor, bb.rotation); - drawBuildingGhost(painter, bb.type, anchor, bb.rotation, valid); + drawBuildingGhost(painter, bb.type, anchor, bb.rotation, valid, + /*showPortTargetGlyphs*/ false); } } @@ -1634,7 +1643,7 @@ void GameWorldView::drawOverlays(QPainter& painter) void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type, QPoint anchorTile, Rotation rotation, - bool valid) + bool valid, bool showPortTargetGlyphs) { const BuildingDef* def = findBuildingDef(type); if (!def) { return; } @@ -1688,7 +1697,21 @@ void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type, for (const Port& port : parsed.outputPorts) { drawPortGlyph(painter, anchorTile + portBodyTile(port.tile, port.direction), - port.direction, lineColor); + port.direction, lineColor, /*centered*/ false); + } + + // REQ-UI-PORT-TARGET-GLYPH: while in builder mode, additionally mark each + // output port's target cell (the cell just outside the footprint the port + // pushes into) with a directional glyph, previewing where output will flow. + // The Tunnel Entry is excluded — it receives items from any of its non-mouth + // edges rather than emitting into a single adjacent cell. + if (showPortTargetGlyphs && type != BuildingType::TunnelEntry) + { + for (const Port& port : parsed.outputPorts) + { + drawPortGlyph(painter, anchorTile + port.tile, port.direction, + lineColor, /*centered*/ true); + } } painter.setOpacity(1.0); diff --git a/src/ui/GameWorldView.h b/src/ui/GameWorldView.h index 835cf4a..fc2e396 100644 --- a/src/ui/GameWorldView.h +++ b/src/ui/GameWorldView.h @@ -175,11 +175,13 @@ private: std::vector buildingsInBox(QPoint cornerA, QPoint cornerB) const; QVector2D widgetToWorld(QPoint widgetPt) const; - void drawPortGlyph(QPainter& painter, QPoint bodyTile, - Rotation direction, const QColor& color); + void drawPortGlyph(QPainter& painter, QPoint tile, + Rotation direction, const QColor& color, + bool centered); void drawBuildingGhost(QPainter& painter, BuildingType type, - QPoint anchorTile, Rotation rotation, bool valid); + QPoint anchorTile, Rotation rotation, bool valid, + bool showPortTargetGlyphs); void placeBlueprintAtTile(QPoint center);