[Icons] Migrate UI glyphs to palette-token SVGs (#7595)

* [Icons] Migrate UI glyphs to palette-token SVGs

Runtime inversion is not a theming system: it rotates hue, breaks duotone art
and mishandles alpha, and a QPixmap snapshot cannot follow a palette change.
Redraw the top-level UI glyph set on a 24x24 grid with `currentColor` as the
paint token, drop Inkscape/Sodipodi cruft, and delete the icons whose metaphor
was duplicated (cogwheel/gear -> settings, scale_balanced -> scales,
update.png -> reload).

Load the glyphs through `loadThemedIcon` so the engine resolves the token from
the palette on every request, and let `themePixmap` use the same resolution for
one-shot pixmaps. `loadColorAdjustedPixmap` is gone; every caller now keeps a
QIcon, which `SettingsButtonWidget::setButtonIcon` accepts instead of a QPixmap.

Content art (mana, counters, countries) keeps its authored colors.

Add a render test covering aspect ratio, palette flips, icon modes and
high-DPI pixmaps.

* [Tests] Keep the icon render test QApplication alive until exit

Creating it as a function-local static tears it down before Qt's library statics
at exit, and libQt6Network then runs QObject destructors against freed memory —
a SEGV the sanitizer leg reports after the tests have already passed. Leak the
application instead, the usual pattern for a test binary.

* [Icons] Render lock and dropdown glyphs through the icon engine

Both generators rendered the sentinel SVG to a fixed height x height pixmap
at DPR 1. The pre-migration path rendered larger and let QIcon scale it, so
on a 2x display the games-list lock (13px) and the banner dropdown arrow
(24px) came back crisp; the new path hands the widget a DPR-1 bitmap that
gets upscaled and blurred.

- The games list asks the themed engine for `icons/lock` directly, so the
  item view paints it at the device pixel ratio and the lock also follows
  HighlightedText on a selected row.
- The dropdown goes through `loadThemedIcon(...).pixmap(size, dpr)`, which
  keeps the glyph's aspect ratio and renders at the requested ratio.
- LockPixmapGenerator has no consumer left, so it and its cache are gone.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-11-04 18:39:41 +01:00 • committed by GitHub
parent 020d9e8dcb
commit 627c7a83aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
97 changed files with 543 additions and 9711 deletions

View file

@ -1,6 +1,6 @@
#include "visual_database_display_filter_toolbar_widget.h"
#include "../../pixel_map_generator.h"
#include "../../theme_icon.h"
#include "../deck_editor/card_database_view.h"
#include "../quick_settings/settings_button_widget.h"
#include "card_database_display_model.h"
@ -45,13 +45,13 @@ VisualDatabaseDisplayFilterToolbarWidget::VisualDatabaseDisplayFilterToolbarWidg
sortGroupBox = new QGroupBox(this);
filterGroupBox = new QGroupBox(this);
auto scalePixmap = [](const QString &fileName) { return QIcon(QPixmap(fileName)).pixmap({20, 20}); };
auto scalePixmap = [](const QString &prefix) { return loadThemedIcon(prefix).pixmap({20, 20}); };
sortByLabel = new QLabel(this);
sortByLabel->setPixmap(scalePixmap("theme:icons/sort_arrow_down"));
sortByLabel->setPixmap(scalePixmap("icons/sort_arrow_down"));
filterByLabel = new QLabel(this);
filterByLabel->setPixmap(scalePixmap("theme:icons/filter"));
filterByLabel->setPixmap(scalePixmap("icons/filter"));
sortColumnCombo = new QComboBox(this);
sortColumnCombo->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents);
@ -89,22 +89,22 @@ VisualDatabaseDisplayFilterToolbarWidget::VisualDatabaseDisplayFilterToolbarWidg
});
quickFilterSaveLoadWidget = new SettingsButtonWidget(this);
quickFilterSaveLoadWidget->setButtonIcon(themePixmap(QStringLiteral("icons/floppy_disk")));
quickFilterSaveLoadWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/floppy_disk")));
quickFilterNameWidget = new SettingsButtonWidget(this);
quickFilterNameWidget->setButtonIcon(themePixmap(QStringLiteral("icons/pen_to_square")));
quickFilterNameWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/pen_to_square")));
quickFilterMainTypeWidget = new SettingsButtonWidget(this);
quickFilterMainTypeWidget->setButtonIcon(themePixmap(QStringLiteral("icons/circle_half_stroke")));
quickFilterMainTypeWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/circle_half_stroke")));
quickFilterSubTypeWidget = new SettingsButtonWidget(this);
quickFilterSubTypeWidget->setButtonIcon(themePixmap(QStringLiteral("icons/dragon")));
quickFilterSubTypeWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/dragon")));
quickFilterSetWidget = new SettingsButtonWidget(this);
quickFilterSetWidget->setButtonIcon(themePixmap(QStringLiteral("icons/scroll")));
quickFilterSetWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/scroll")));
quickFilterFormatLegalityWidget = new SettingsButtonWidget(this);
quickFilterFormatLegalityWidget->setButtonIcon(themePixmap(QStringLiteral("icons/scale_balanced")));
quickFilterFormatLegalityWidget->setButtonIcon(loadThemedIcon(QStringLiteral("icons/scales")));
retranslateUi();
}

View file

@ -4,7 +4,9 @@
#include "../../../filters/filter_tree_model.h"
#include "../../../filters/syntax_help.h"
#include "../../key_signals.h"
#include "../../pixel_map_generator.h"
#include "../../theme_icon.h"
#include "../cards/card_info_picture_widget.h"
#include "../cards/card_info_picture_with_text_overlay_widget.h"
#include "../cards/card_size_widget.h"
#include "../deck_editor/card_database_view.h"
#include "../general/layout_containers/flow_widget.h"
@ -79,8 +81,8 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
searchEdit->setObjectName("searchEdit");
searchEdit->setPlaceholderText(tr("Search by card name (or search expressions)"));
searchEdit->setClearButtonEnabled(true);
searchEdit->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
auto help = searchEdit->addAction(themePixmap(QStringLiteral("icons/info")), QLineEdit::TrailingPosition);
searchEdit->addAction(loadThemedIcon(QStringLiteral("icons/search")), QLineEdit::LeadingPosition);
auto help = searchEdit->addAction(loadThemedIcon(QStringLiteral("icons/info")), QLineEdit::TrailingPosition);
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); });
setFocusProxy(searchEdit);
@ -154,7 +156,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
clearFilterWidget = new QToolButton();
clearFilterWidget->setFixedSize(32, 32);
clearFilterWidget->setIcon(themePixmap(QStringLiteral("icons/delete")));
clearFilterWidget->setIcon(loadThemedIcon(QStringLiteral("icons/delete")));
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
filterModel->blockSignals(true);
filterModel->filterTree()->blockSignals(true);