#pragma once #include #include #include #include #include #include #include class QPainter; class QRectF; struct VisualsConfig; // Rasterizes and caches per-item icon SVGs, and composes them onto the item's colored // square (REQ-UI-ITEM-ICON). Item icons are self-contained, full-color SVGs loaded from // a directory, one file per item type named after the item's id (e.g. "iron_ore.svg"). // // The square is the item's `fill` and `outline` from visuals.toml with the icon inset // within it, and it backs the icon both in the game world and wherever the UI displays // an item as an item: the selection panel's item chips (REQ-UI-SINGLE-SELECTION, // REQ-UI-HQ-PANEL), and every recipe drawn as a line -- the recipe summary, the // selection dialog's option buttons, the item production tooltip // (REQ-UI-RECIPE-SUMMARY, REQ-UI-SELECT-OPTIONS, REQ-UI-ITEM-TOOLTIP). Defined here // once rather than per widget, in // two forms: paintItem() for the world's fractional geometry, getSquarePixmap() for // widgets that want a ready-made pixmap. // // The bare icon of getPixmap() has one remaining use: an inline icon standing in for the // item's name beside a number -- building blocks beside a cost or a stock // (REQ-UI-BLOCKS-ICON), scrap beside the amount left in debris (REQ-UI-DEBRIS-PANEL) -- // which is a decoration on a line of text rather than an item display and takes no // square. getInlineItemIcon() in IconCaption.h is how callers ask for that form. // // A missing icon file is not an error: hasIcon() returns false for it and the item shows // its colored square alone. class ItemIconCache { public: // iconDir is the directory holding the ".svg" icon files (typically // "/../icons/items"). visuals supplies the per-item square colors and // must outlive the cache; its contents may be replaced on a restart (REQ-CFG-RELOAD), // which is what clearPixmapCache() is for. ItemIconCache(const QString& iconDir, const VisualsConfig* visuals); // True if an icon SVG file exists for the given item id. Loads the file's bytes // on first query and remembers the result (including absence) so repeated calls // are cheap. bool hasIcon(const std::string& itemId); // Paints the item's colored square into rect and its icon inset within it // (REQ-UI-ITEM-ICON). Takes the rect as a QRectF so the world can keep painting at // sub-pixel geometry. An item with no visuals entry gets no square, one with no icon // file no icon; with neither, this paints nothing. void paintItem(QPainter& painter, const QRectF& rect, const std::string& itemId); // The same composition rasterized to a sizePx*sizePx pixmap for widget use, cached // per (item id, size) so it is rendered once and reused. Returns a null pixmap only // when the item has neither a visuals entry nor an icon file, which is the one case // in which a caller has nothing to show and falls back to text. QPixmap getSquarePixmap(const std::string& itemId, int sizePx); // Returns the item's icon alone, without its square, rasterized to a transparent // sizePx*sizePx pixmap and cached per (item id, size) so it is rendered once and // reused across frames (REQ-UI-ITEM-ICON). Returns a null pixmap if the item has no // icon file (callers should gate on hasIcon()). QPixmap getPixmap(const std::string& itemId, int sizePx); // The same bare icon sized to the height of `font`'s text, for the inline form above: // an icon standing in for the item's name on a line of text. Null when the item has // no icon file, which is not an error -- the caller names the item in words instead. QPixmap getInlineIcon(const std::string& itemId, const QFont& font); // Drops every rasterized pixmap. Called when the visuals are reloaded on a restart // (REQ-CFG-RELOAD), because the composed squares carry the colors they were painted // with; they are re-rasterized on next use. void clearPixmapCache(); private: // Returns the raw SVG bytes for an item id, loading and caching them on first // access. An absent file caches an empty QByteArray so it is not retried. const QByteArray& getSvg(const std::string& itemId); // Shared rasterize-and-cache step. cacheKey distinguishes the bare and squared // variants of one item within the single pixmap cache. QPixmap getPixmap(const std::string& cacheKey, const std::string& itemId, int sizePx, bool withSquare); QString m_iconDir; const VisualsConfig* m_visuals; // Not owned; lives in MainWindow. std::map m_svgById; std::map, QPixmap> m_pixmapCache; };