mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
[Icons] Keep semantic red and green on themed glyphs
The one-glyph cutover recolored every icon from a single palette role, so a disabled deck, a not-ready player and a remove button all lost the red or green that carried their meaning. Add Positive and Negative application colors beside the accents, ship scheme-appropriate defaults for every theme, and resolve them through ThemeManager. Icons now take an IconTint: a palette role for structural glyphs, or a semantic role for states and add/remove actions. A disabled semantic icon falls back to the disabled foreground; on a selected row a semantic tint keeps its color only while it stays legible on the highlight, and a palette tint keeps the existing WindowText -> HighlightedText swap.
This commit is contained in:
parent
df74917cb0
commit
db4e07e55d
35 changed files with 339 additions and 53 deletions
|
|
@ -30,7 +30,7 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
|||
typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i));
|
||||
}
|
||||
|
||||
QPushButton *ok = new QPushButton(loadThemedIcon(QStringLiteral("icons/increment")), QString());
|
||||
QPushButton *ok = new QPushButton(loadThemedIcon(QStringLiteral("icons/increment"), AppColor::Positive), QString());
|
||||
ok->setObjectName("ok");
|
||||
ok->setMaximumSize(20, 20);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor,
|
|||
QWidget *parent)
|
||||
: QTreeWidget(parent), tabSupervisor(_tabSupervisor), client(_client), game(_game), gameStarted(false)
|
||||
{
|
||||
readyIcon = loadThemedIcon(QStringLiteral("icons/ready_start"));
|
||||
notReadyIcon = loadThemedIcon(QStringLiteral("icons/not_ready_start"));
|
||||
readyIcon = loadThemedIcon(QStringLiteral("icons/ready_start"), AppColor::Positive);
|
||||
notReadyIcon = loadThemedIcon(QStringLiteral("icons/not_ready_start"), AppColor::Negative);
|
||||
concededIcon = loadThemedIcon(QStringLiteral("icons/conceded"));
|
||||
playerIcon = loadThemedIcon(QStringLiteral("icons/player"));
|
||||
judgeIcon = loadThemedIcon(QStringLiteral("icons/scales"));
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ PaletteConfig fromAccent(const QColor &accent, int intensity, const QString &sch
|
|||
// the lightened, desaturated companion used for button-gradient highlights.
|
||||
cfg.appColors[AppColor::AccentStrong] = hl;
|
||||
cfg.appColors[AppColor::AccentSoft] = hsl(accent.lightness() + 60, qRound(accent.hslSaturation() * 70 / 100.0));
|
||||
// Semantic roles stay independent of the accent: a generated palette must
|
||||
// still paint add/ready green and remove/not-ready red.
|
||||
cfg.appColors[AppColor::Positive] = defaultAppColor(AppColor::Positive, dark);
|
||||
cfg.appColors[AppColor::Negative] = defaultAppColor(AppColor::Negative, dark);
|
||||
|
||||
// BrightText
|
||||
QColor bright;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
#include <QEvent>
|
||||
#include <QFont>
|
||||
#include <QFrame>
|
||||
|
|
@ -62,6 +63,10 @@ static const QMap<QPalette::ColorRole, const char *> ROLE_DESCRIPTIONS = {
|
|||
static const QMap<AppColor::Role, const char *> APP_ROLE_DESCRIPTIONS = {
|
||||
{AppColor::AccentStrong, QT_TR_NOOP("Vivid primary accent (e.g. home-tab button gradient start)")},
|
||||
{AppColor::AccentSoft, QT_TR_NOOP("Lightened, desaturated accent (e.g. home-tab button gradient end)")},
|
||||
{AppColor::Positive,
|
||||
QT_TRANSLATE_NOOP("PaletteGridWidget", "Positive state and additive actions (ready, add, increment)")},
|
||||
{AppColor::Negative,
|
||||
QT_TRANSLATE_NOOP("PaletteGridWidget", "Negative state and removal actions (not ready, remove, decrement)")},
|
||||
};
|
||||
|
||||
PaletteGridWidget::PaletteGridWidget(QWidget *parent) : QWidget(parent)
|
||||
|
|
@ -179,7 +184,7 @@ void PaletteGridWidget::buildGrid(QWidget *host)
|
|||
}
|
||||
|
||||
auto *label = new QLabel(QString(appEnum.valueToKey(role)), host);
|
||||
label->setToolTip(APP_ROLE_DESCRIPTIONS.value(role, {}));
|
||||
label->setToolTip(QCoreApplication::translate("PaletteGridWidget", APP_ROLE_DESCRIPTIONS.value(role, {})));
|
||||
label->setContentsMargins(4, 2, 8, 2);
|
||||
grid->addWidget(label, row, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <QList>
|
||||
#include <QMetaEnum>
|
||||
#include <QPair>
|
||||
#include <QStringLiteral>
|
||||
#include <QTextStream>
|
||||
#include <qnamespace.h>
|
||||
#include <utility>
|
||||
|
|
@ -451,3 +452,19 @@ FontConfig FontConfig::fromThemeDir(const QString &themeDirPath)
|
|||
|
||||
return fromFile(QDir(themeDirPath).absoluteFilePath(fileName()));
|
||||
}
|
||||
|
||||
QColor defaultAppColor(AppColor::Role role, bool dark)
|
||||
{
|
||||
switch (role) {
|
||||
case AppColor::AccentStrong:
|
||||
case AppColor::AccentSoft:
|
||||
// Derived from the palette highlight by ThemeManager::appColor().
|
||||
return {};
|
||||
case AppColor::Positive:
|
||||
return QColor(dark ? QStringLiteral("#6dd58c") : QStringLiteral("#1b7f3b"));
|
||||
case AppColor::Negative:
|
||||
return QColor(dark ? QStringLiteral("#ff8a80") : QStringLiteral("#b3261e"));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ enum Role
|
|||
{
|
||||
AccentStrong,
|
||||
AccentSoft,
|
||||
Positive,
|
||||
Negative,
|
||||
};
|
||||
Q_ENUM_NS(Role)
|
||||
} // namespace AppColor
|
||||
|
|
@ -41,6 +43,16 @@ enum Role
|
|||
Q_ENUM_NS(Role)
|
||||
} // namespace AppFont
|
||||
|
||||
/**
|
||||
* @brief Fallback for an application color role when the active theme does not
|
||||
* define one.
|
||||
*
|
||||
* Accent roles return an invalid QColor because ThemeManager derives them from
|
||||
* the palette highlight. Semantic roles return an opaque, scheme-appropriate
|
||||
* default so a theme written before the role existed still renders it sensibly.
|
||||
*/
|
||||
QColor defaultAppColor(AppColor::Role role, bool dark);
|
||||
|
||||
struct ThemeConfig
|
||||
{
|
||||
QString colorScheme;
|
||||
|
|
|
|||
|
|
@ -23,19 +23,74 @@
|
|||
#include <QStyle>
|
||||
#include <QSvgRenderer>
|
||||
#include <QtGlobal>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @brief Palette color that replaces `currentColor`, following the icon mode.
|
||||
* @brief WCAG relative luminance, used to test a tint against a background.
|
||||
*/
|
||||
QByteArray sentinelColor(QIcon::Mode mode, QPalette::ColorRole role)
|
||||
double relativeLuminance(const QColor &color)
|
||||
{
|
||||
const auto linear = [](double channel) {
|
||||
channel /= 255.0;
|
||||
return channel <= 0.03928 ? channel / 12.92 : std::pow((channel + 0.055) / 1.055, 2.4);
|
||||
};
|
||||
return 0.2126 * linear(color.red()) + 0.7152 * linear(color.green()) + 0.0722 * linear(color.blue());
|
||||
}
|
||||
|
||||
double contrastRatio(const QColor &first, const QColor &second)
|
||||
{
|
||||
const double a = relativeLuminance(first);
|
||||
const double b = relativeLuminance(second);
|
||||
return (qMax(a, b) + 0.05) / (qMin(a, b) + 0.05);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IconTint::IconTint(QPalette::ColorRole role) : paletteRole(role)
|
||||
{
|
||||
}
|
||||
|
||||
IconTint::IconTint(AppColor::Role role) : source(Source::AppColor), appRole(role)
|
||||
{
|
||||
}
|
||||
|
||||
QColor IconTint::resolve(QIcon::Mode mode) const
|
||||
{
|
||||
if (source == Source::AppColor) {
|
||||
// A disabled control must not keep signalling its semantic color.
|
||||
if (mode == QIcon::Disabled) {
|
||||
return qApp->palette().color(QPalette::Disabled, QPalette::WindowText);
|
||||
}
|
||||
const QColor color = themeManager->appColor(appRole);
|
||||
if (mode != QIcon::Selected) {
|
||||
return color;
|
||||
}
|
||||
// Selected rows paint their icon on the highlight colour. Keep the
|
||||
// semantic tint when it stays legible there; otherwise the glyph would
|
||||
// vanish into the selection.
|
||||
constexpr double MIN_SELECTED_CONTRAST = 3.0;
|
||||
const QColor highlight = qApp->palette().color(QPalette::Active, QPalette::Highlight);
|
||||
return contrastRatio(color, highlight) >= MIN_SELECTED_CONTRAST
|
||||
? color
|
||||
: qApp->palette().color(QPalette::Active, QPalette::HighlightedText);
|
||||
}
|
||||
|
||||
const QPalette::ColorGroup group = mode == QIcon::Disabled ? QPalette::Disabled : QPalette::Active;
|
||||
const QPalette::ColorRole effective =
|
||||
mode == QIcon::Selected && role == QPalette::WindowText ? QPalette::HighlightedText : role;
|
||||
return qApp->palette().color(group, effective).name(QColor::HexRgb).toLatin1();
|
||||
mode == QIcon::Selected && paletteRole == QPalette::WindowText ? QPalette::HighlightedText : paletteRole;
|
||||
return qApp->palette().color(group, effective);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @brief Color that replaces `currentColor`, following the icon mode.
|
||||
*/
|
||||
QByteArray sentinelColor(QIcon::Mode mode, const IconTint &tint)
|
||||
{
|
||||
return tint.resolve(mode).name(QColor::HexRgb).toLatin1();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +161,7 @@ QString cacheKey(const QString &path, const QByteArray &variant, const QSize &si
|
|||
class ThemeSvgIconEngine final : public QObject, public QIconEngine
|
||||
{
|
||||
public:
|
||||
ThemeSvgIconEngine(QString _prefix, QPalette::ColorRole _role) : prefix(std::move(_prefix)), role(_role)
|
||||
ThemeSvgIconEngine(QString _prefix, IconTint _tint) : prefix(std::move(_prefix)), tint(_tint)
|
||||
{
|
||||
if (themeManager) {
|
||||
// A theme switch changes the resolved asset (scheme-qualified
|
||||
|
|
@ -120,7 +175,7 @@ public:
|
|||
|
||||
QIconEngine *clone() const override
|
||||
{
|
||||
return new ThemeSvgIconEngine(prefix, role);
|
||||
return new ThemeSvgIconEngine(prefix, tint);
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State) override
|
||||
|
|
@ -238,7 +293,7 @@ private:
|
|||
// with its own colors varies by mode (Disabled is generated). A color
|
||||
// variant is never a bare digit, so the two key spaces cannot collide.
|
||||
const QByteArray variant =
|
||||
resolvedHasSentinel ? sentinelColor(mode, role) : QByteArray::number(static_cast<int>(mode));
|
||||
resolvedHasSentinel ? sentinelColor(mode, tint) : QByteArray::number(static_cast<int>(mode));
|
||||
const QString key = cacheKey(resolvedPath, variant, pixelSize, devicePixelRatio);
|
||||
const auto cached = cache.constFind(key);
|
||||
if (cached != cache.constEnd()) {
|
||||
|
|
@ -266,7 +321,7 @@ private:
|
|||
}
|
||||
|
||||
QString prefix;
|
||||
QPalette::ColorRole role;
|
||||
IconTint tint;
|
||||
mutable QHash<QString, QPixmap> cache;
|
||||
mutable QString resolvedPath;
|
||||
mutable QString resolvedThemePath;
|
||||
|
|
@ -279,12 +334,12 @@ private:
|
|||
};
|
||||
} // namespace
|
||||
|
||||
QIcon loadThemedIcon(QStringView prefix, QPalette::ColorRole role)
|
||||
QIcon loadThemedIcon(QStringView prefix, IconTint tint)
|
||||
{
|
||||
return QIcon(new ThemeSvgIconEngine(prefix.toString(), role));
|
||||
return QIcon(new ThemeSvgIconEngine(prefix.toString(), tint));
|
||||
}
|
||||
|
||||
QPixmap loadSentinelSvgPixmap(const QString &resolvedPath, QPalette::ColorRole role, const QSize &size)
|
||||
QPixmap loadSentinelSvgPixmap(const QString &resolvedPath, IconTint tint, const QSize &size)
|
||||
{
|
||||
if (!resolvedPath.endsWith(QStringLiteral(".svg"), Qt::CaseInsensitive)) {
|
||||
return {};
|
||||
|
|
@ -295,6 +350,6 @@ QPixmap loadSentinelSvgPixmap(const QString &resolvedPath, QPalette::ColorRole r
|
|||
return {};
|
||||
}
|
||||
|
||||
const QByteArray color = qApp->palette().color(role).name(QColor::HexRgb).toLatin1();
|
||||
const QByteArray color = tint.resolve(QIcon::Normal).name(QColor::HexRgb).toLatin1();
|
||||
return renderSvg(resolveSvgColorSentinel(svg, color), size, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#ifndef THEME_ICON_H
|
||||
#define THEME_ICON_H
|
||||
|
||||
#include "theme_config.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QIcon>
|
||||
#include <QPalette>
|
||||
#include <QPixmap>
|
||||
|
|
@ -13,6 +16,41 @@
|
|||
#include <QString>
|
||||
#include <QStringView>
|
||||
|
||||
/**
|
||||
* @brief Selects the color that replaces the `currentColor` sentinel.
|
||||
*
|
||||
* A palette role follows Qt's structural palette. An application color carries
|
||||
* meaning that QPalette cannot express, such as positive and negative states.
|
||||
* Callers pick the role by intent; the theme owns the concrete value.
|
||||
*/
|
||||
class IconTint
|
||||
{
|
||||
public:
|
||||
IconTint() = default;
|
||||
IconTint(QPalette::ColorRole role); // implicit: existing palette-role callers
|
||||
IconTint(AppColor::Role role); // implicit: semantic callers
|
||||
|
||||
/**
|
||||
* @brief Resolves the concrete color for an icon mode.
|
||||
*
|
||||
* Disabled application colors resolve to the disabled foreground so an
|
||||
* unavailable control does not keep signalling its semantic color. Selected
|
||||
* palette colors keep the existing WindowText -> HighlightedText swap.
|
||||
*/
|
||||
QColor resolve(QIcon::Mode mode) const;
|
||||
|
||||
private:
|
||||
enum class Source
|
||||
{
|
||||
Palette,
|
||||
AppColor,
|
||||
};
|
||||
|
||||
Source source = Source::Palette;
|
||||
QPalette::ColorRole paletteRole = QPalette::WindowText;
|
||||
AppColor::Role appRole = AppColor::AccentStrong;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builds a palette-aware icon from a `theme:` asset.
|
||||
*
|
||||
|
|
@ -24,11 +62,11 @@
|
|||
*
|
||||
* @param prefix Asset prefix relative to the `theme:` search path, with no file
|
||||
* extension (for example `icons/search`), matching themePixmap().
|
||||
* @param role Palette role whose color replaces the sentinel. Selected glyphs
|
||||
* use HighlightedText unless a role other than WindowText is given.
|
||||
* @param tint Color that replaces the sentinel: a palette role or a semantic
|
||||
* application color. Defaults to WindowText.
|
||||
* @return An icon that follows the application palette.
|
||||
*/
|
||||
QIcon loadThemedIcon(QStringView prefix, QPalette::ColorRole role = QPalette::WindowText);
|
||||
QIcon loadThemedIcon(QStringView prefix, IconTint tint = {});
|
||||
|
||||
/**
|
||||
* @brief Renders a resolved theme SVG when it carries the `currentColor` sentinel.
|
||||
|
|
@ -38,13 +76,12 @@ QIcon loadThemedIcon(QStringView prefix, QPalette::ColorRole role = QPalette::Wi
|
|||
*
|
||||
* @param resolvedPath Asset path relative to the `theme:` search path, as
|
||||
* returned by ThemeManager::assetPath (includes extension).
|
||||
* @param role Palette role whose color replaces the sentinel.
|
||||
* @param tint Color that replaces the sentinel: a palette role or a semantic
|
||||
* application color. Defaults to WindowText.
|
||||
* @param size Pixel size to render at; an empty size uses the SVG's intrinsic size.
|
||||
* @return The recolored pixmap, or a null pixmap when the asset is not a
|
||||
* sentinel-carrying SVG.
|
||||
*/
|
||||
QPixmap loadSentinelSvgPixmap(const QString &resolvedPath,
|
||||
QPalette::ColorRole role = QPalette::WindowText,
|
||||
const QSize &size = {});
|
||||
QPixmap loadSentinelSvgPixmap(const QString &resolvedPath, IconTint tint = {}, const QSize &size = {});
|
||||
|
||||
#endif // THEME_ICON_H
|
||||
|
|
|
|||
|
|
@ -639,14 +639,23 @@ QColor ThemeManager::appColor(AppColor::Role role) const
|
|||
// unconditionally keeps every Qt version rendering identically.
|
||||
const QColor accent = qApp->palette().color(QPalette::Active, QPalette::Highlight);
|
||||
|
||||
if (role == AppColor::AccentSoft) {
|
||||
constexpr int SOFT_SATURATION_PERCENT = 70;
|
||||
constexpr int SOFT_LIGHTNESS_OFFSET = 60;
|
||||
switch (role) {
|
||||
case AppColor::AccentStrong:
|
||||
return accent;
|
||||
case AppColor::AccentSoft: {
|
||||
constexpr int SOFT_SATURATION_PERCENT = 70;
|
||||
constexpr int SOFT_LIGHTNESS_OFFSET = 60;
|
||||
|
||||
// Light end of the gradient: same hue, softened and lightened
|
||||
return QColor::fromHsl(qMax(0, accent.hslHue()),
|
||||
qBound(0, qRound(accent.hslSaturation() * SOFT_SATURATION_PERCENT / 100.0), 255),
|
||||
qBound(0, accent.lightness() + SOFT_LIGHTNESS_OFFSET, 255));
|
||||
// Light end of the gradient: same hue, softened and lightened
|
||||
return QColor::fromHsl(qMax(0, accent.hslHue()),
|
||||
qBound(0, qRound(accent.hslSaturation() * SOFT_SATURATION_PERCENT / 100.0), 255),
|
||||
qBound(0, accent.lightness() + SOFT_LIGHTNESS_OFFSET, 255));
|
||||
}
|
||||
case AppColor::Positive:
|
||||
case AppColor::Negative:
|
||||
// Semantic colors are independent of the accent: a missing role must
|
||||
// not silently paint "remove" in the theme's highlight color.
|
||||
return defaultAppColor(role, isDarkModeActive());
|
||||
}
|
||||
|
||||
return accent;
|
||||
|
|
|
|||
|
|
@ -147,7 +147,8 @@ public:
|
|||
void previewFonts(const FontConfig &cfg);
|
||||
|
||||
// Resolves an application color role: the theme's stored [AppColors] value
|
||||
// when present, otherwise a palette-accent-derived fallback.
|
||||
// when present, otherwise a palette-accent-derived fallback for accents and
|
||||
// a scheme-appropriate semantic default for positive / negative.
|
||||
QColor appColor(AppColor::Role role) const;
|
||||
/** @brief Resolves an application font role: the theme's stored [Fonts]
|
||||
* value when present, otherwise the application font. Roles that
|
||||
|
|
|
|||
|
|
@ -83,12 +83,14 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
|
|||
&DeckEditorDatabaseDisplayWidget::onRelatedCardClicked);
|
||||
|
||||
aAddCard = new QAction(QString(), this);
|
||||
aAddCard->setIcon(loadThemedIcon(QStringLiteral("icons/arrow_right")));
|
||||
aAddCard->setIcon(loadThemedIcon(QStringLiteral("icons/arrow_right"), AppColor::Positive));
|
||||
connect(aAddCard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck);
|
||||
auto *tbAddCard = new QToolButton(this);
|
||||
tbAddCard->setDefaultAction(aAddCard);
|
||||
|
||||
aAddCardToSideboard = new QAction(QString(), this);
|
||||
// Sideboard is a destination, not a positive state: its distinct glyph
|
||||
// keeps the target legible without competing with the green main-deck add.
|
||||
aAddCardToSideboard->setIcon(loadThemedIcon(QStringLiteral("icons/arrow_right_sideboard")));
|
||||
connect(aAddCardToSideboard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
|
||||
auto *tbAddCardToSideboard = new QToolButton(this);
|
||||
|
|
|
|||
|
|
@ -248,19 +248,19 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
|||
&DeckEditorDeckDockWidget::applyActiveGroupCriteria);
|
||||
|
||||
aIncrement = new QAction(QString(), this);
|
||||
aIncrement->setIcon(loadThemedIcon(QStringLiteral("icons/increment")));
|
||||
aIncrement->setIcon(loadThemedIcon(QStringLiteral("icons/increment"), AppColor::Positive));
|
||||
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrementSelection);
|
||||
auto *tbIncrement = new QToolButton(this);
|
||||
tbIncrement->setDefaultAction(aIncrement);
|
||||
|
||||
aDecrement = new QAction(QString(), this);
|
||||
aDecrement->setIcon(loadThemedIcon(QStringLiteral("icons/decrement")));
|
||||
aDecrement->setIcon(loadThemedIcon(QStringLiteral("icons/decrement"), AppColor::Negative));
|
||||
connect(aDecrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actDecrementSelection);
|
||||
auto *tbDecrement = new QToolButton(this);
|
||||
tbDecrement->setDefaultAction(aDecrement);
|
||||
|
||||
aRemoveCard = new QAction(QString(), this);
|
||||
aRemoveCard->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
aRemoveCard->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
connect(aRemoveCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actRemoveCard);
|
||||
auto *tbRemoveCard = new QToolButton(this);
|
||||
tbRemoveCard->setDefaultAction(aRemoveCard);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ void DeckEditorFilterDockWidget::createFiltersDock()
|
|||
connect(filterBuilder, &FilterBuilder::add, filterModel, &FilterTreeModel::addFilter);
|
||||
|
||||
aClearFilterOne = new QAction(QString(), this);
|
||||
aClearFilterOne->setIcon(loadThemedIcon(QStringLiteral("icons/decrement")));
|
||||
aClearFilterOne->setIcon(loadThemedIcon(QStringLiteral("icons/decrement"), AppColor::Negative));
|
||||
connect(aClearFilterOne, &QAction::triggered, this, &DeckEditorFilterDockWidget::actClearFilterOne);
|
||||
|
||||
aClearFilterAll = new QAction(QString(), this);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
|
|||
previousHosts = new QComboBox(this);
|
||||
|
||||
btnDeleteServer = new QPushButton(this);
|
||||
btnDeleteServer->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
btnDeleteServer->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
btnDeleteServer->setToolTip(tr("Delete the currently selected saved server"));
|
||||
btnDeleteServer->setFixedWidth(30);
|
||||
|
||||
|
|
|
|||
|
|
@ -108,10 +108,10 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
|
|||
&DlgEditTokens::tokenSelectionChanged);
|
||||
|
||||
QAction *aAddToken = new QAction(tr("Add token"), this);
|
||||
aAddToken->setIcon(loadThemedIcon(QStringLiteral("icons/increment")));
|
||||
aAddToken->setIcon(loadThemedIcon(QStringLiteral("icons/increment"), AppColor::Positive));
|
||||
connect(aAddToken, &QAction::triggered, this, &DlgEditTokens::actAddToken);
|
||||
QAction *aRemoveToken = new QAction(tr("Remove token"), this);
|
||||
aRemoveToken->setIcon(loadThemedIcon(QStringLiteral("icons/decrement")));
|
||||
aRemoveToken->setIcon(loadThemedIcon(QStringLiteral("icons/decrement"), AppColor::Negative));
|
||||
connect(aRemoveToken, &QAction::triggered, this, &DlgEditTokens::actRemoveToken);
|
||||
|
||||
auto *databaseToolBar = new QToolBar;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
|||
previousHosts = new QComboBox(this);
|
||||
|
||||
btnDeleteServer = new QPushButton(this);
|
||||
btnDeleteServer->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
btnDeleteServer->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
btnDeleteServer->setToolTip(tr("Delete the currently selected saved server"));
|
||||
btnDeleteServer->setFixedWidth(30);
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
}
|
||||
|
||||
aAdd = new QAction(this);
|
||||
aAdd->setIcon(loadThemedIcon(QStringLiteral("icons/increment")));
|
||||
aAdd->setIcon(loadThemedIcon(QStringLiteral("icons/increment"), AppColor::Positive));
|
||||
connect(aAdd, &QAction::triggered, this, &DeckEditorSettingsPage::actAddURL);
|
||||
|
||||
aEdit = new QAction(this);
|
||||
|
|
@ -88,7 +88,7 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
connect(aEdit, &QAction::triggered, this, &DeckEditorSettingsPage::actEditURL);
|
||||
|
||||
aRemove = new QAction(this);
|
||||
aRemove->setIcon(loadThemedIcon(QStringLiteral("icons/decrement")));
|
||||
aRemove->setIcon(loadThemedIcon(QStringLiteral("icons/decrement"), AppColor::Negative));
|
||||
connect(aRemove, &QAction::triggered, this, &DeckEditorSettingsPage::actRemoveURL);
|
||||
|
||||
aRateLimit = new QAction(this);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ MessagesSettingsPage::MessagesSettingsPage()
|
|||
}
|
||||
|
||||
aAdd = new QAction(this);
|
||||
aAdd->setIcon(loadThemedIcon(QStringLiteral("icons/increment")));
|
||||
aAdd->setIcon(loadThemedIcon(QStringLiteral("icons/increment"), AppColor::Positive));
|
||||
connect(aAdd, &QAction::triggered, this, &MessagesSettingsPage::actAdd);
|
||||
|
||||
aEdit = new QAction(this);
|
||||
|
|
@ -154,7 +154,7 @@ MessagesSettingsPage::MessagesSettingsPage()
|
|||
connect(aEdit, &QAction::triggered, this, &MessagesSettingsPage::actEdit);
|
||||
|
||||
aRemove = new QAction(this);
|
||||
aRemove->setIcon(loadThemedIcon(QStringLiteral("icons/decrement")));
|
||||
aRemove->setIcon(loadThemedIcon(QStringLiteral("icons/decrement"), AppColor::Negative));
|
||||
connect(aRemove, &QAction::triggered, this, &MessagesSettingsPage::actRemove);
|
||||
|
||||
auto *messageToolBar = new QToolBar;
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
|||
aNewLocalFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
|
||||
connect(aNewLocalFolder, &QAction::triggered, this, &TabDeckStorage::actNewLocalFolder);
|
||||
aDeleteLocalDeck = new QAction(this);
|
||||
aDeleteLocalDeck->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
aDeleteLocalDeck->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
connect(aDeleteLocalDeck, &QAction::triggered, this, &TabDeckStorage::actDeleteLocalDeck);
|
||||
|
||||
aOpenDecksFolder = new QAction(this);
|
||||
|
|
@ -217,7 +217,7 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
|
|||
aNewFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
|
||||
connect(aNewFolder, &QAction::triggered, this, &TabDeckStorage::actNewFolder);
|
||||
aDeleteRemoteDeck = new QAction(this);
|
||||
aDeleteRemoteDeck->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
aDeleteRemoteDeck->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
connect(aDeleteRemoteDeck, &QAction::triggered, this, &TabDeckStorage::actDeleteRemoteDeck);
|
||||
|
||||
aShareDecks = new QAction(this);
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ QGroupBox *TabReplays::createLeftLayout()
|
|||
aNewLocalFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
|
||||
connect(aNewLocalFolder, &QAction::triggered, this, &TabReplays::actNewLocalFolder);
|
||||
aDeleteLocalReplay = new QAction(this);
|
||||
aDeleteLocalReplay->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
aDeleteLocalReplay->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
connect(aDeleteLocalReplay, &QAction::triggered, this, &TabReplays::actDeleteLocalReplay);
|
||||
|
||||
aOpenReplaysFolder = new QAction(this);
|
||||
|
|
@ -217,7 +217,7 @@ QGroupBox *TabReplays::createRightLayout()
|
|||
aKeep->setIcon(loadThemedIcon(QStringLiteral("icons/lock")));
|
||||
connect(aKeep, &QAction::triggered, this, &TabReplays::actKeepRemoteReplay);
|
||||
aDeleteRemoteReplay = new QAction(this);
|
||||
aDeleteRemoteReplay->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row")));
|
||||
aDeleteRemoteReplay->setIcon(loadThemedIcon(QStringLiteral("icons/remove_row"), AppColor::Negative));
|
||||
connect(aDeleteRemoteReplay, &QAction::triggered, this, &TabReplays::actDeleteRemoteReplay);
|
||||
aGetReplayCode = new QAction(this);
|
||||
aGetReplayCode->setIcon(loadThemedIcon(QStringLiteral("icons/share")));
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
|||
|
||||
clearFilterWidget = new QToolButton();
|
||||
clearFilterWidget->setFixedSize(32, 32);
|
||||
clearFilterWidget->setIcon(loadThemedIcon(QStringLiteral("icons/delete")));
|
||||
clearFilterWidget->setIcon(loadThemedIcon(QStringLiteral("icons/delete"), AppColor::Negative));
|
||||
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #4a82e6
|
|||
[AppColors]
|
||||
AccentStrong = #3a6fd6
|
||||
AccentSoft = #8fb8f2
|
||||
Positive = #6dd58c
|
||||
Negative = #ff8a80
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #2f6fd6
|
|||
[AppColors]
|
||||
AccentStrong = #3a6fd6
|
||||
AccentSoft = #8fb8f2
|
||||
Positive = #1b7f3b
|
||||
Negative = #b3261e
|
||||
|
||||
|
|
|
|||
|
|
@ -71,3 +71,5 @@ Accent = #ff1e1e1e
|
|||
[AppColors]
|
||||
AccentStrong = #ff139740
|
||||
AccentSoft = #ffc9fd62
|
||||
Positive = #6dd58c
|
||||
Negative = #ff8a80
|
||||
|
|
|
|||
|
|
@ -71,3 +71,5 @@ Accent = #fff0f0f0
|
|||
[AppColors]
|
||||
AccentStrong = #ff139740
|
||||
AccentSoft = #ffc9fd62
|
||||
Positive = #1b7f3b
|
||||
Negative = #b3261e
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #c9995a
|
|||
[AppColors]
|
||||
AccentStrong = #b7823b
|
||||
AccentSoft = #e4c58f
|
||||
Positive = #6dd58c
|
||||
Negative = #ff8a80
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #a5712f
|
|||
[AppColors]
|
||||
AccentStrong = #b7823b
|
||||
AccentSoft = #e4c58f
|
||||
Positive = #1b7f3b
|
||||
Negative = #b3261e
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #6a4df0
|
|||
[AppColors]
|
||||
AccentStrong = #5b3ee0
|
||||
AccentSoft = #a28bf7
|
||||
Positive = #6dd58c
|
||||
Negative = #ff8a80
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #5a3ee2
|
|||
[AppColors]
|
||||
AccentStrong = #5b3ee0
|
||||
AccentSoft = #a28bf7
|
||||
Positive = #1b7f3b
|
||||
Negative = #b3261e
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
# The System theme derives all of its colors from the platform palette
|
||||
# (e.g. qt6ct's custom color scheme on Linux), so it must NOT ship palette
|
||||
# overrides. Only the identity app colors are provided here, so buttons keep
|
||||
# their classic greens while the actual palette stays native to the OS.
|
||||
# overrides. Only the identity and semantic app colors are provided here, so
|
||||
# buttons keep their classic greens while the actual palette stays native to
|
||||
# the OS.
|
||||
[AppColors]
|
||||
AccentStrong = #ff148c3c
|
||||
AccentSoft = #ff78c850
|
||||
Positive = #ff6dd58c
|
||||
Negative = #ffff8a80
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
# The System theme derives all of its colors from the platform palette
|
||||
# (e.g. qt6ct's custom color scheme on Linux), so it must NOT ship palette
|
||||
# overrides. Only the identity app colors are provided here, so buttons keep
|
||||
# their classic greens while the actual palette stays native to the OS.
|
||||
# overrides. Only the identity and semantic app colors are provided here, so
|
||||
# buttons keep their classic greens while the actual palette stays native to
|
||||
# the OS.
|
||||
[AppColors]
|
||||
AccentStrong = #ff148c3c
|
||||
AccentSoft = #ff78c850
|
||||
Positive = #ff1b7f3b
|
||||
Negative = #ffb3261e
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #8fa6c0
|
|||
[AppColors]
|
||||
AccentStrong = #54687e
|
||||
AccentSoft = #9db0c4
|
||||
Positive = #6dd58c
|
||||
Negative = #ff8a80
|
||||
|
||||
|
|
|
|||
|
|
@ -71,4 +71,6 @@ Accent = #54687e
|
|||
[AppColors]
|
||||
AccentStrong = #54687e
|
||||
AccentSoft = #9db0c4
|
||||
Positive = #1b7f3b
|
||||
Negative = #b3261e
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue