Compare commits
23 Commits
ui_changes
...
37a7a7499a
| Author | SHA1 | Date | |
|---|---|---|---|
| 37a7a7499a | |||
| 5794a51c9a | |||
| 09858f4b62 | |||
| ca49b9dbec | |||
| 79650ae211 | |||
| c0b009c548 | |||
| 7ae5f8c4dc | |||
| 9f574fa05e | |||
| e5d689c8d8 | |||
| 0b8f5eccd6 | |||
| 40415e663b | |||
| 7a098edf72 | |||
| 365641feb7 | |||
| 4b5e288632 | |||
| cab7244b00 | |||
| 980fad272f | |||
| 68a43a7d98 | |||
| 1f754de431 | |||
| f61f0bf761 | |||
| 075e44d295 | |||
| 2289277e12 | |||
| cc0ef856e3 | |||
| 603f8063e9 |
@@ -109,40 +109,40 @@ glyph = "E"
|
||||
# --- ores ---
|
||||
|
||||
[items.iron_ore]
|
||||
fill = "#8a5a4a"
|
||||
outline = "#201010"
|
||||
fill = "#47271c"
|
||||
outline = "#a65b42"
|
||||
|
||||
[items.copper_ore]
|
||||
fill = "#c47a3a"
|
||||
outline = "#3a1a0a"
|
||||
fill = "#deb592"
|
||||
outline = "#826a56"
|
||||
|
||||
[items.quartz]
|
||||
fill = "#e0d4f0"
|
||||
outline = "#40345a"
|
||||
fill = "#4f3d66"
|
||||
outline = "#9776c4"
|
||||
|
||||
# --- smelted basics ---
|
||||
|
||||
[items.iron_ingot]
|
||||
fill = "#b0b0b8"
|
||||
outline = "#202028"
|
||||
fill = "#535357"
|
||||
outline = "#97979e"
|
||||
|
||||
[items.copper_ingot]
|
||||
fill = "#d48a4a"
|
||||
outline = "#402010"
|
||||
fill = "#663810"
|
||||
outline = "#b07746"
|
||||
|
||||
[items.silicon]
|
||||
fill = "#33415e"
|
||||
outline = "#0e1420"
|
||||
fill = "#737f99"
|
||||
outline = "#373f4f"
|
||||
|
||||
# --- salvage loop ---
|
||||
|
||||
[items.scrap]
|
||||
fill = "#7a7268"
|
||||
outline = "#201a14"
|
||||
fill = "#998e81"
|
||||
outline = "#574b3d"
|
||||
|
||||
[items.voidsteel]
|
||||
fill = "#4a3a6a"
|
||||
outline = "#151020"
|
||||
fill = "#82759c"
|
||||
outline = "#3f374f"
|
||||
|
||||
# --- basic components ---
|
||||
|
||||
@@ -151,106 +151,106 @@ fill = "#e09a50"
|
||||
outline = "#3a2008"
|
||||
|
||||
[items.steel_plate]
|
||||
fill = "#8a92a0"
|
||||
outline = "#22262c"
|
||||
fill = "#202836"
|
||||
outline = "#54698c"
|
||||
|
||||
[items.copper_coil]
|
||||
fill = "#d07030"
|
||||
outline = "#381808"
|
||||
fill = "#cca287"
|
||||
outline = "#755d4d"
|
||||
|
||||
[items.building_block]
|
||||
fill = "#c8b070"
|
||||
outline = "#302810"
|
||||
fill = "#544724"
|
||||
outline = "#a18845"
|
||||
|
||||
# --- advanced components ---
|
||||
|
||||
[items.control_chip]
|
||||
fill = "#2ea35a"
|
||||
outline = "#0a2a14"
|
||||
fill = "#74b08b"
|
||||
outline = "#42634e"
|
||||
|
||||
[items.capacitor_bank]
|
||||
fill = "#d0a030"
|
||||
outline = "#302408"
|
||||
|
||||
[items.hardened_steel]
|
||||
fill = "#6a7280"
|
||||
outline = "#181c22"
|
||||
fill = "#818999"
|
||||
outline = "#3e4859"
|
||||
|
||||
[items.ceramic_plate]
|
||||
fill = "#e0d8c8"
|
||||
outline = "#3a3428"
|
||||
|
||||
[items.drive_unit]
|
||||
fill = "#4a6ad0"
|
||||
outline = "#101a38"
|
||||
fill = "#92a4de"
|
||||
outline = "#545f80"
|
||||
|
||||
# --- capital components ---
|
||||
|
||||
[items.voidsteel_plate]
|
||||
fill = "#7a5aaa"
|
||||
outline = "#1c1038"
|
||||
fill = "#9986b5"
|
||||
outline = "#544766"
|
||||
|
||||
[items.capital_core]
|
||||
fill = "#b040d0"
|
||||
outline = "#280c30"
|
||||
fill = "#420c52"
|
||||
outline = "#9444ab"
|
||||
|
||||
# --- module items ---
|
||||
|
||||
[items.railgun_s_module]
|
||||
fill = "#691313"
|
||||
outline = "#f3ff4f"
|
||||
fill = "#bf7e7e"
|
||||
outline = "#664343"
|
||||
|
||||
[items.railgun_m_module]
|
||||
fill = "#892020"
|
||||
outline = "#f3ff4f"
|
||||
fill = "#b07474"
|
||||
outline = "#593b3b"
|
||||
|
||||
[items.railgun_l_module]
|
||||
fill = "#a92d2d"
|
||||
outline = "#f3ff4f"
|
||||
fill = "#b07474"
|
||||
outline = "#593b3b"
|
||||
|
||||
[items.salvager_module]
|
||||
fill = "#b2cfdd"
|
||||
outline = "#236137"
|
||||
|
||||
[items.repair_tool_module]
|
||||
fill = "#2e9ba3"
|
||||
outline = "#689275"
|
||||
fill = "#0b4347"
|
||||
outline = "#38868c"
|
||||
|
||||
[items.armor_plates_module]
|
||||
fill = "#808080"
|
||||
outline = "#202020"
|
||||
fill = "#999999"
|
||||
outline = "#545454"
|
||||
|
||||
[items.sensor_booster_module]
|
||||
fill = "#40a0ff"
|
||||
outline = "#102840"
|
||||
fill = "#a0c9f2"
|
||||
outline = "#607991"
|
||||
|
||||
[items.maneuvering_thrusters_module]
|
||||
fill = "#5090e0"
|
||||
outline = "#142438"
|
||||
fill = "#92b4de"
|
||||
outline = "#566982"
|
||||
|
||||
[items.afterburner_module]
|
||||
fill = "#6080c0"
|
||||
outline = "#182030"
|
||||
fill = "#1d2e52"
|
||||
outline = "#486db5"
|
||||
|
||||
[items.weapon_upgrade_module]
|
||||
fill = "#ff4040"
|
||||
outline = "#401010"
|
||||
|
||||
[items.weapon_primer_module]
|
||||
fill = "#e03838"
|
||||
outline = "#380e0e"
|
||||
fill = "#e69797"
|
||||
outline = "#855858"
|
||||
|
||||
[items.weapon_stabilizer_module]
|
||||
fill = "#c03030"
|
||||
outline = "#300c0c"
|
||||
fill = "#c78383"
|
||||
outline = "#6e4848"
|
||||
|
||||
[items.drone_bay_module]
|
||||
fill = "#cc66ff"
|
||||
outline = "#331040"
|
||||
|
||||
[items.drone_hangar_module]
|
||||
fill = "#9933cc"
|
||||
outline = "#260c33"
|
||||
fill = "#8c689e"
|
||||
outline = "#42314a"
|
||||
|
||||
# --- ship hulls (outline matches the ship's fleet color in [ships.*]) ---
|
||||
|
||||
@@ -283,8 +283,8 @@ fill = "#1b1b1b"
|
||||
outline = "#ff5533"
|
||||
|
||||
[items.carrier_hull]
|
||||
fill = "#1b1b1b"
|
||||
outline = "#cc66ff"
|
||||
fill = "#310f42"
|
||||
outline = "#8542a6"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Ships
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[world]
|
||||
height_tiles = 40
|
||||
height_tiles = 30
|
||||
refund_percentage = 100
|
||||
deconstruction_time_seconds = 0.1
|
||||
starting_building_blocks = 200
|
||||
@@ -15,7 +15,7 @@ building_blocks_tooltip = "Building blocks are the currency for construction. Sp
|
||||
artifact_tooltip = "Artifacts are the key to victory. Earn one by choosing the artifact reward when you destroy a set of enemy defence stations. Collect enough of them to win the game."
|
||||
|
||||
[regions]
|
||||
asteroid_width_tiles = 60
|
||||
asteroid_width_tiles = 40
|
||||
player_buffer_width_tiles = 20
|
||||
contest_zone_width_tiles = 60
|
||||
enemy_buffer_width_tiles = 20
|
||||
|
||||
@@ -91,7 +91,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
|
||||
## Game World
|
||||
|
||||
- REQ-GW-COORDS: Tile coordinates are integer `(x, y)`. The origin `(0, 0)` is the first column of space — the tile immediately to the right of the asteroid's right edge at game start, at the top of the world. X grows right; Y grows down. All asteroid tiles have `x < 0`; asteroid left-expansions add tiles at increasingly negative X. The origin never shifts.
|
||||
- REQ-GW-TILE-SIZE: Tiles are square. The tile size in pixels is derived automatically so that the world height (in tiles) exactly fills the game world view's height in pixels. Items on belts are rendered at half-tile size (drawn as an item icon, or a colored square as the fallback — REQ-UI-ITEM-ICON); when multiple items occupy the same tile they are spaced quarter-tile apart along the direction of travel and overlap, rendered in ascending order of progress — the least-progressed item is drawn first (bottom) and the furthest-progressed item is drawn last (on top). Items emerging from a building's output port are rendered by these same rules on that port's output belt (REQ-MAT-OUTPUT-EMERGE).
|
||||
- REQ-GW-TILE-SIZE: Tiles are square. The tile size in pixels is derived automatically so that the world height (in tiles) exactly fills the game world view's height in pixels. Items on belts are rendered at half-tile size (drawn as a colored square carrying the item's icon, or the square alone when the item has no icon — REQ-UI-ITEM-ICON); when multiple items occupy the same tile they are spaced quarter-tile apart along the direction of travel and overlap, rendered in ascending order of progress — the least-progressed item is drawn first (bottom) and the furthest-progressed item is drawn last (on top). Items emerging from a building's output port are rendered by these same rules on that port's output belt (REQ-MAT-OUTPUT-EMERGE).
|
||||
- REQ-GW-BELT-CAPACITY: Belt tiles and tunnel entry/exit tiles each hold up to four items simultaneously, queued one behind the other in the direction of travel. Splitter tiles hold up to four items: two unassigned items (progress < 0.5, not yet routed to an output) and one item per output slot (progress ≥ 0.5, committed to a specific output direction). Output-slot items are rendered on top of unassigned items; when both output slots are occupied, their rendering order follows the clockwise port order starting from East.
|
||||
- REQ-GW-BELT-SPEED: Items on belts move at `world.toml [world].belt_speed_tiles_per_second` tiles per second (default 2).
|
||||
- REQ-GW-HEIGHT: The world height (in tiles) is read from `world.toml [world].height_tiles`.
|
||||
@@ -477,7 +477,7 @@ The screen is a single column: a header bar across the top and the game world vi
|
||||
|
||||
Because the contest-zone boundaries shift as the scrollable area grows with each push (REQ-GW-PUSH-EXPAND, REQ-GW-SCROLL-LIMIT), the ramp bands are recomputed from the current contest-zone boundaries. This is a presentation-only concern and does not affect the simulation, consistent with REQ-UI-NO-ZOOM.
|
||||
- REQ-UI-WORLD-ICON: In the game world, a building is drawn with an icon's glyph symbol centered on its footprint, in place of the letter identity glyph. The icon is an SVG loaded from `data/icons/buildings/`; only the icon's glyph is drawn in the world — in a contrasting ink (white over dark fills, dark over light fills) so it stays legible — and its colored chip background is omitted, because the footprint is already filled with the building's `visuals.toml` fill color. This applies to the production buildings (Miner, Smelter, Assembler, Reprocessing Plant, Shipyard, Salvage Bay), the HQ, and the player and enemy defence stations, wherever the identity label appears: operational buildings, construction sites (REQ-UI-CONSTRUCTION-PROGRESS), and the builder-mode and blueprint-placement ghosts. **Belts, splitters, and tunnels are excluded** — they keep their existing tile rendering so their orientation and flow stay readable (a centered icon would obscure direction). Their build-menu buttons still use icons (REQ-UI-BUILD-ICON); in particular the shared Tunnel button's `tunnel_entry.svg` is a build-button icon only, not a world icon. The directional output-port glyphs (REQ-UI-PORT-GLYPH, REQ-UI-PORT-TARGET-GLYPH) are a separate indicator and are unaffected. A building or station with no icon file falls back to its `visuals.toml` text glyph; a type with neither icon nor glyph shows no identity label. A missing icon is not an error, consistent with REQ-UI-BUILD-ICON.
|
||||
- REQ-UI-ITEM-ICON: In the game world, an item is drawn with its **item icon** in place of the colored square of REQ-GW-TILE-SIZE. The icon is a self-contained, full-color SVG (rendered as-is, unlike the glyph-only building icons of REQ-UI-WORLD-ICON), loaded at runtime from `data/icons/items/` — a sibling of the config directory, read the same way as the building icons (REQ-UI-BUILD-ICON) — one file per item type named after the item's id (e.g. `iron_ore.svg`). It fills the item's half-tile rect, keeping the size, spacing, and draw-order rules of REQ-GW-TILE-SIZE, and applies wherever an item is drawn: on belts, splitters, and tunnel ends, and while emerging from or sinking into a building port (REQ-MAT-OUTPUT-EMERGE, REQ-MAT-INPUT-INTAKE). An item type with no icon file falls back to its `visuals.toml` colored square (`fill` + `outline`); a missing icon is not an error, consistent with REQ-UI-BUILD-ICON. For performance, each item icon is rasterized to a pixmap cached per target pixel size — re-rasterized only when the tile pixel size changes (e.g. on view resize) — rather than re-rendered from vector every frame.
|
||||
- REQ-UI-ITEM-ICON: In the game world, an item is drawn as its `visuals.toml` colored square (`fill` + `outline`, the square of REQ-GW-TILE-SIZE) carrying its **item icon** on top. The square is drawn for every item, with or without an icon: it is what gives the item contrast against the tile beneath it, and its outline is what separates neighbouring items where they overlap on a belt. The icon is a self-contained, full-color SVG (rendered as-is, unlike the glyph-only building icons of REQ-UI-WORLD-ICON), loaded at runtime from `data/icons/items/` — a sibling of the config directory, read the same way as the building icons (REQ-UI-BUILD-ICON) — one file per item type named after the item's id (e.g. `iron_ore.svg`). The square fills the item's half-tile rect, keeping the size, spacing, and draw-order rules of REQ-GW-TILE-SIZE; the icon is drawn **inset** within that rect so a frame of the square's color stays visible all around it — required because each icon's viewBox is cropped tight to its artwork, so an icon drawn at the full rect would cover the square entirely. This applies wherever an item is drawn: on belts, splitters, and tunnel ends, and while emerging from or sinking into a building port (REQ-MAT-OUTPUT-EMERGE, REQ-MAT-INPUT-INTAKE). An item type with no icon file shows the colored square alone; a missing icon is not an error, consistent with REQ-UI-BUILD-ICON. The colored square is a game-world treatment only: the item chips and selection dialogs of the UI panels (REQ-UI-SINGLE-SELECTION, REQ-UI-SELECT-BUTTON) show the icon without it. For performance, each item icon is rasterized to a pixmap cached per target pixel size — re-rasterized only when the tile pixel size changes (e.g. on view resize) — rather than re-rendered from vector every frame.
|
||||
- REQ-UI-CONSTRUCTION-PROGRESS: Construction sites display the building's identity symbol centered on the footprint (same as an operational building) — its icon glyph, or the text glyph as a fallback (REQ-UI-WORLD-ICON). Below the symbol — or centered on the footprint if the building has neither an icon nor a glyph — a construction progress percentage is shown (integer, e.g. `42%`), increasing from 0% to 100% as construction completes.
|
||||
- REQ-UI-PORT-GLYPH: Every output port of every building is indicated by a directional glyph drawn on the port's tile. The glyph is a `>` rotated to face the port's exit direction (`>` for East, `^` for North, `<` for West, `v` for South). It is drawn at the midpoint between the tile center and the tile edge that the port exits through (i.e. halfway from center toward the exit edge). The indicator is rendered for all building states: operational buildings, construction sites, and the builder-mode ghost. Buildings with multiple output ports (e.g. splitters) show one indicator per port.
|
||||
- REQ-UI-PORT-TARGET-GLYPH: While in builder mode (REQ-BLD-BUILDER-MODE), the builder-mode ghost additionally shows, for each of the building's output ports, a directional glyph drawn centered in the port's **target cell** — the cell immediately outside the footprint that the port pushes into, i.e. the cell the surface-mask output-port indicator occupies (see Surface Mask Format). As in REQ-UI-PORT-GLYPH the glyph is a `>` rotated to face the port's exit direction (`>` East, `^` North, `<` West, `v` South), previewing where the port's output will go before placement. This is in addition to the on-tile port glyph of REQ-UI-PORT-GLYPH, and — unlike that indicator — is shown only for the builder-mode ghost, not for operational buildings, construction sites, or the blueprint-placement ghost (REQ-UI-BLUEPRINT-PLACE). A building with multiple output ports (e.g. a splitter) shows one target-cell glyph per port. The target-cell glyph is drawn larger than the on-tile port glyph so it stands out as the flow-direction preview. Exceptions: the Tunnel Entry shows no target-cell glyph, because it receives items (which may arrive from any of its non-mouth edges, REQ-BLD-TUNNEL-ENTRY) rather than emitting into a single adjacent cell; the Shipyard shows none either, because its output port is a ship-spawn point (REQ-SHP-SPAWN-PLAYER) rather than a belt-item output (REQ-MAT-OUTPUT-EMERGE).
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "SelectionPanel.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QList>
|
||||
#include <QScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include <QVBoxLayout>
|
||||
@@ -265,16 +263,9 @@ void SelectionPanel::placeIn(const QRect& viewRect, const std::vector<QRect>& oc
|
||||
// laid out, does the width it reports. Measuring at whatever width the panel
|
||||
// happens to have carries the previous card's shape into this one.
|
||||
//
|
||||
// Each measurement re-runs the card's layouts -- every one of them, not just the
|
||||
// body's own. Changing a label's text posts a LayoutRequest to the widget holding it
|
||||
// and that event is only delivered when the event loop next runs, so a layout nested
|
||||
// inside the card still reports the width of the text before the change: measuring
|
||||
// here and re-measuring on the following refresh then gives two different answers,
|
||||
// and the panel visibly resizes a frame after its content changed. Re-activating
|
||||
// them all is what a delivered LayoutRequest would have done.
|
||||
//
|
||||
// Cards are built and discarded whole, so this is also what discards the previous
|
||||
// card's cached hints, and what accounts for the parts a card hides and shows as it
|
||||
// Each measurement re-runs the body layout. Cards are built and discarded whole, so
|
||||
// its cached hint describes the card before this one until it is invalidated, and
|
||||
// re-running it is also what accounts for the parts a card hides and shows as it
|
||||
// refreshes. The polish belongs to the same step: a freshly created chip reports an
|
||||
// unstyled hint until the stylesheet has reached it, and the chips carry border and
|
||||
// padding that change their size.
|
||||
@@ -282,16 +273,6 @@ void SelectionPanel::placeIn(const QRect& viewRect, const std::vector<QRect>& oc
|
||||
{
|
||||
m_body->resize(widthPx, m_body->height());
|
||||
m_body->ensurePolished();
|
||||
|
||||
// Deepest first, so no layout is re-activated from children that are themselves
|
||||
// still stale. findChildren walks parents before children, hence the reverse.
|
||||
const QList<QLayout*> nested = m_body->findChildren<QLayout*>();
|
||||
for (QList<QLayout*>::const_reverse_iterator it = nested.rbegin();
|
||||
it != nested.rend(); ++it)
|
||||
{
|
||||
(*it)->invalidate();
|
||||
(*it)->activate();
|
||||
}
|
||||
m_body->layout()->invalidate();
|
||||
m_body->layout()->activate();
|
||||
return m_body->sizeHint();
|
||||
|
||||
@@ -520,8 +520,8 @@ void WorldRenderer::drawPortItems(QPainter& painter, const WorldCoordinates& coo
|
||||
}
|
||||
}
|
||||
|
||||
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile item icon, or the
|
||||
// colored-square fallback (REQ-UI-ITEM-ICON), via the same draw path.
|
||||
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile colored square carrying the
|
||||
// item's icon (REQ-UI-ITEM-ICON), via the same draw path.
|
||||
const std::function<void(const ItemType&, QPointF)> drawItem =
|
||||
[&](const ItemType& type, QPointF worldPos)
|
||||
{
|
||||
@@ -544,25 +544,34 @@ void WorldRenderer::drawWorldItem(QPainter& painter, const std::string& itemId,
|
||||
const QRectF itemRect(center.x() - halfPx, center.y() - halfPx,
|
||||
halfPx * 2, halfPx * 2);
|
||||
|
||||
// Prefer the item's icon (REQ-UI-ITEM-ICON); it is rasterized once at the current
|
||||
// half-tile pixel size and cached, so this is a plain pixmap blit per frame.
|
||||
if (m_itemIcons && m_itemIcons->hasIcon(itemId))
|
||||
{
|
||||
int sizePx = qRound(static_cast<qreal>(halfPx * 2.0f));
|
||||
if (sizePx < 1) { sizePx = 1; }
|
||||
painter.drawPixmap(itemRect, m_itemIcons->getPixmap(itemId, sizePx),
|
||||
QRectF(0, 0, sizePx, sizePx));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: the colored square from visuals.toml (REQ-GW-TILE-SIZE).
|
||||
// The colored square from visuals.toml (REQ-GW-TILE-SIZE) backs every item, icon or
|
||||
// not: it is what gives the item contrast against the tile beneath it, and its dark
|
||||
// outline is what separates neighbouring items where they overlap on a belt.
|
||||
const std::map<std::string, ItemVisuals>::const_iterator it =
|
||||
m_visuals.items.find(itemId);
|
||||
if (it == m_visuals.items.end()) { return; }
|
||||
painter.fillRect(itemRect, it->second.fill);
|
||||
painter.setPen(QPen(it->second.outline, 1));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawRect(itemRect);
|
||||
if (it != m_visuals.items.end())
|
||||
{
|
||||
painter.fillRect(itemRect, it->second.fill);
|
||||
painter.setPen(QPen(it->second.outline, 1));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawRect(itemRect);
|
||||
}
|
||||
|
||||
if (!m_itemIcons || !m_itemIcons->hasIcon(itemId)) { return; }
|
||||
|
||||
// The icon goes on top, inset so a frame of the square's color stays visible all
|
||||
// around it (REQ-UI-ITEM-ICON). The inset is needed because each icon's viewBox is
|
||||
// cropped tight to its artwork: drawn at the full rect, a solid icon would cover the
|
||||
// square entirely. It is rasterized once at the inset pixel size and cached, so this
|
||||
// is a plain pixmap blit per frame.
|
||||
constexpr double kIconInsetFraction = 0.15;
|
||||
const double inset = kIconInsetFraction * static_cast<double>(halfPx * 2.0f);
|
||||
const QRectF iconRect = itemRect.adjusted(inset, inset, -inset, -inset);
|
||||
|
||||
int sizePx = qRound(iconRect.width());
|
||||
if (sizePx < 1) { sizePx = 1; }
|
||||
painter.drawPixmap(iconRect, m_itemIcons->getPixmap(itemId, sizePx),
|
||||
QRectF(0, 0, sizePx, sizePx));
|
||||
}
|
||||
|
||||
void WorldRenderer::drawBeltItems(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
|
||||
@@ -113,9 +113,9 @@ private:
|
||||
void drawOverlays(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
// Draws a single item centered at widget-space `center`, spanning `halfPx` in
|
||||
// each direction (a half-tile). Uses the item's icon when one exists
|
||||
// (REQ-UI-ITEM-ICON), otherwise falls back to the colored square from
|
||||
// visuals.toml. Shared by drawBeltItems and drawPortItems.
|
||||
// each direction (a half-tile): the colored square from visuals.toml, carrying
|
||||
// the item's icon inset on top of it when one exists (REQ-UI-ITEM-ICON).
|
||||
// Shared by drawBeltItems and drawPortItems.
|
||||
void drawWorldItem(QPainter& painter, const std::string& itemId,
|
||||
QPointF center, float halfPx);
|
||||
void drawPortGlyph(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
|
||||
@@ -32,38 +32,6 @@ const int kSymbolSizePx = 20;
|
||||
const int kCardSpacingPx = 6;
|
||||
const int kHeaderSpacingPx = 6;
|
||||
|
||||
// The Salvage Bay has no recipe and no cycle: its two states say whether it is holding
|
||||
// scrap, not whether it is producing (REQ-BLD-SALVAGE-BAY, REQ-UI-SELECTION-STATUS).
|
||||
QString getStatusCaption(ProductionStatus status, bool isSalvageBay)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ProductionStatus::Unconfigured: return QObject::tr("no recipe");
|
||||
case ProductionStatus::Producing:
|
||||
return isSalvageBay ? QObject::tr("holding scrap")
|
||||
: QObject::tr("producing");
|
||||
case ProductionStatus::Starved:
|
||||
return isSalvageBay ? QObject::tr("empty") : QObject::tr("missing input");
|
||||
case ProductionStatus::Blocked: return QObject::tr("output full");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
// Every caption the status slot can end up showing for this building, so the header can
|
||||
// keep its width as the state changes rather than the panel jumping with it.
|
||||
QStringList getAllStatusCaptions(bool isSalvageBay)
|
||||
{
|
||||
QStringList captions;
|
||||
for (ProductionStatus status : { ProductionStatus::Unconfigured,
|
||||
ProductionStatus::Producing,
|
||||
ProductionStatus::Starved,
|
||||
ProductionStatus::Blocked })
|
||||
{
|
||||
captions << getStatusCaption(status, isSalvageBay);
|
||||
}
|
||||
return captions;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -200,26 +168,25 @@ void SelectionContent::setProductionStatusSlot(const Building& building)
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isSalvageBay = (building.type == BuildingType::SalvageBay);
|
||||
// Room for every caption this building can show, so the panel keeps its width as the
|
||||
// building's state changes rather than jumping with it.
|
||||
reserveSlotFor(getAllStatusCaptions(isSalvageBay));
|
||||
|
||||
const StatusLightVisuals& colors = m_context.visuals->statusLight;
|
||||
QColor dotColor;
|
||||
// The Salvage Bay has no recipe and no cycle: its two states say whether it is
|
||||
// holding scrap, not whether it is producing (REQ-BLD-SALVAGE-BAY).
|
||||
const bool isSalvageBay = (building.type == BuildingType::SalvageBay);
|
||||
switch (*status)
|
||||
{
|
||||
case ProductionStatus::Unconfigured: dotColor = colors.grey; break;
|
||||
case ProductionStatus::Producing: dotColor = colors.green; break;
|
||||
case ProductionStatus::Starved: dotColor = colors.red; break;
|
||||
case ProductionStatus::Blocked: dotColor = colors.yellow; break;
|
||||
case ProductionStatus::Unconfigured:
|
||||
setSlot(colors.grey, tr("no recipe"));
|
||||
break;
|
||||
case ProductionStatus::Producing:
|
||||
setSlot(colors.green, isSalvageBay ? tr("holding scrap") : tr("producing"));
|
||||
break;
|
||||
case ProductionStatus::Starved:
|
||||
setSlot(colors.red, isSalvageBay ? tr("empty") : tr("missing input"));
|
||||
break;
|
||||
case ProductionStatus::Blocked:
|
||||
setSlot(colors.yellow, tr("output full"));
|
||||
break;
|
||||
}
|
||||
setSlot(dotColor, getStatusCaption(*status, isSalvageBay));
|
||||
}
|
||||
|
||||
void SelectionContent::reserveSlotFor(const QStringList& captions)
|
||||
{
|
||||
m_statusPill->reserveFor(captions);
|
||||
}
|
||||
|
||||
void SelectionContent::refreshConstruction()
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <QColor>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
#include "BuildingId.h"
|
||||
@@ -80,11 +79,6 @@ protected:
|
||||
void setCountSlot(int count);
|
||||
void clearSlot();
|
||||
|
||||
// Reserves header room for the widest caption the slot will ever show. The panel is
|
||||
// sized to its card (REQ-UI-SELECTION-PANEL), so without this it changes width every
|
||||
// time the caption does -- and a card whose chips wrap changes height with it.
|
||||
void reserveSlotFor(const QStringList& captions);
|
||||
|
||||
// Fills the right slot from the building's production status, mapped to the same
|
||||
// colors and states the world's status light uses (REQ-UI-SELECTION-STATUS). Leaves
|
||||
// the slot empty for a type that has no status light.
|
||||
|
||||
@@ -33,16 +33,3 @@ QString getBehaviorLabel(BehaviorKind kind)
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList getAllBehaviorLabels()
|
||||
{
|
||||
QStringList labels;
|
||||
for (BehaviorKind kind : { BehaviorKind::Retreat, BehaviorKind::Attack,
|
||||
BehaviorKind::SalvageScrap, BehaviorKind::Repair,
|
||||
BehaviorKind::Rally, BehaviorKind::Standby,
|
||||
BehaviorKind::Advance })
|
||||
{
|
||||
labels << getBehaviorLabel(kind);
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "BehaviorKind.h"
|
||||
#include "BuildingType.h"
|
||||
@@ -14,8 +13,3 @@ QString getBuildingTypeName(BuildingType type);
|
||||
// Name of the behavior currently governing a ship, for the ship card's header slot
|
||||
// (REQ-UI-SHIP-BEHAVIOR). Empty when no behavior has won yet, which shows no slot.
|
||||
QString getBehaviorLabel(BehaviorKind kind);
|
||||
|
||||
// Every name getBehaviorLabel can return. A ship's behavior changes as it fights, so the
|
||||
// header reserves room for the widest of these rather than letting the panel change
|
||||
// width each time (REQ-UI-SELECTION-PANEL).
|
||||
QStringList getAllBehaviorLabels();
|
||||
|
||||
@@ -21,10 +21,6 @@ ShipContent::ShipContent(const SelectionContext& context,
|
||||
m_statsPanel = new ShipStatsPanel(context.config, this);
|
||||
getRuntimeLayout()->addWidget(m_statsPanel);
|
||||
|
||||
// A ship's behavior changes as it fights, so the header holds room for the longest
|
||||
// name rather than the panel resizing under the player each time it does.
|
||||
reserveSlotFor(getAllBehaviorLabels());
|
||||
|
||||
EntityAdmin& admin = context.sim->getAdmin();
|
||||
if (admin.isValid(m_entity) && admin.hasAll<ShipIdentityComponent>(m_entity))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "StatusPill.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QGuiApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
@@ -50,23 +49,6 @@ StatusPill::StatusPill(QWidget* parent)
|
||||
hide();
|
||||
}
|
||||
|
||||
void StatusPill::reserveFor(const QStringList& captions)
|
||||
{
|
||||
if (captions == m_reservedFor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_reservedFor = captions;
|
||||
|
||||
const QFontMetrics metrics(m_captionLabel->font());
|
||||
int widestPx = 0;
|
||||
for (const QString& caption : captions)
|
||||
{
|
||||
widestPx = qMax(widestPx, metrics.horizontalAdvance(caption));
|
||||
}
|
||||
m_captionLabel->setMinimumWidth(widestPx);
|
||||
}
|
||||
|
||||
void StatusPill::setStatus(const QColor& dotColor, const QColor& outlineColor,
|
||||
const QString& caption)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
@@ -24,16 +23,7 @@ public:
|
||||
void setStatus(const QColor& dotColor, const QColor& outlineColor,
|
||||
const QString& caption);
|
||||
|
||||
// Reserves room for the widest of the captions this pill can show, so the header --
|
||||
// and with it the panel, which is sized to its content (REQ-UI-SELECTION-PANEL) --
|
||||
// keeps its width as the caption changes. Without it the whole panel jumps every
|
||||
// time a building's status does, and a card whose chips wrap changes height with it.
|
||||
void reserveFor(const QStringList& captions);
|
||||
|
||||
private:
|
||||
QLabel* m_dotLabel;
|
||||
QLabel* m_captionLabel;
|
||||
// What the width is currently reserved for, so re-reserving the same set on every
|
||||
// refresh costs nothing.
|
||||
QStringList m_reservedFor;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user