mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-27 08:24:39 -07:00
Compare commits
5 commits
48776cfeba
...
2086deff5c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2086deff5c | ||
|
|
3f22089af7 | ||
|
|
9d26e07165 | ||
|
|
12a5b34e42 | ||
|
|
26fb8622e3 |
24 changed files with 299 additions and 99 deletions
4
.github/workflows/desktop-build.yml
vendored
4
.github/workflows/desktop-build.yml
vendored
|
|
@ -3,7 +3,7 @@ name: Build Desktop
|
|||
permissions:
|
||||
actions: write # needed to delete entries in GHA cache (update ccache)
|
||||
attestations: write # needed to persist the attestation.
|
||||
contents: write
|
||||
contents: write # needed for e.g. vcpkg dependency graph updates
|
||||
id-token: write # needed for signing certificate in attestation
|
||||
|
||||
on:
|
||||
|
|
@ -440,6 +440,7 @@ jobs:
|
|||
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
|
||||
CMAKE_GENERATOR_PLATFORM: ${{ matrix.cmake_generator_platform }}
|
||||
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
|
||||
GITHUB_TOKEN: ${{ github.token }} # needed for vcpkg dependency graph updates, see VCPKG_FEATURE_FLAGS
|
||||
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
||||
|
|
@ -450,6 +451,7 @@ jobs:
|
|||
USE_CCACHE: ${{ matrix.use_ccache }}
|
||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
||||
VCPKG_DISABLE_METRICS: 1
|
||||
VCPKG_FEATURE_FLAGS: dependencygraph
|
||||
run: .ci/compile.sh --server --test --vcpkg
|
||||
|
||||
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||
|
|
|
|||
|
|
@ -52,18 +52,14 @@ static void setupParserRules()
|
|||
|
||||
search["Start"] = passthru;
|
||||
search["QueryPartList"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
|
||||
auto matchesFilter = [&deck, &info](const std::any &query) {
|
||||
return std::any_cast<DeckFilter>(query)(deck, info);
|
||||
};
|
||||
return [=](const DeckSearchData &data) {
|
||||
auto matchesFilter = [&data](const std::any &query) { return std::any_cast<DeckFilter>(query)(data); };
|
||||
return std::all_of(sv.begin(), sv.end(), matchesFilter);
|
||||
};
|
||||
};
|
||||
search["ComplexQueryPart"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) {
|
||||
auto matchesFilter = [&deck, &info](const std::any &query) {
|
||||
return std::any_cast<DeckFilter>(query)(deck, info);
|
||||
};
|
||||
return [=](const DeckSearchData &data) {
|
||||
auto matchesFilter = [&data](const std::any &query) { return std::any_cast<DeckFilter>(query)(data); };
|
||||
return std::any_of(sv.begin(), sv.end(), matchesFilter);
|
||||
};
|
||||
};
|
||||
|
|
@ -71,9 +67,7 @@ static void setupParserRules()
|
|||
search["QueryPart"] = passthru;
|
||||
search["NotQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
const auto dependent = std::any_cast<DeckFilter>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) -> bool {
|
||||
return !dependent(deck, info);
|
||||
};
|
||||
return [=](const DeckSearchData &data) -> bool { return !dependent(data); };
|
||||
};
|
||||
|
||||
search["String"] = [](const peg::SemanticValues &sv) -> QString {
|
||||
|
|
@ -125,9 +119,9 @@ static void setupParserRules()
|
|||
auto cardFilter = FilterString(std::any_cast<QString>(sv[0]));
|
||||
auto numberMatcher = sv.size() > 1 ? std::any_cast<NumberMatcher>(sv[1]) : [](int count) { return count > 0; };
|
||||
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
||||
return [=](const DeckSearchData &data) -> bool {
|
||||
int count = 0;
|
||||
auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes();
|
||||
auto cardNodes = data.deck->deckList.getCardNodes();
|
||||
for (auto node : cardNodes) {
|
||||
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
||||
|
|
@ -146,53 +140,49 @@ static void setupParserRules()
|
|||
|
||||
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto name = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive);
|
||||
return [=](const DeckSearchData &data) {
|
||||
return data.deck->deckList.getName().contains(name, Qt::CaseInsensitive);
|
||||
};
|
||||
};
|
||||
|
||||
search["FileNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto name = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
auto filename = QFileInfo(deck->filePath).fileName();
|
||||
return [=](const DeckSearchData &data) {
|
||||
auto filename = QFileInfo(data.filePath).fileName();
|
||||
return filename.contains(name, Qt::CaseInsensitive);
|
||||
};
|
||||
};
|
||||
|
||||
search["PathQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto name = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *, const ExtraDeckSearchInfo &info) {
|
||||
return info.relativeFilePath.contains(name, Qt::CaseInsensitive);
|
||||
};
|
||||
return [=](const DeckSearchData &data) { return data.relativeFilePath.contains(name, Qt::CaseInsensitive); };
|
||||
};
|
||||
|
||||
search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto format = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat();
|
||||
return [=](const DeckSearchData &data) {
|
||||
auto gameFormat = data.deck->deckList.getGameFormat();
|
||||
return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0;
|
||||
};
|
||||
};
|
||||
|
||||
search["CommentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto value = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
auto comments = deck->deckLoader->getDeck().deckList.getComments();
|
||||
return [=](const DeckSearchData &data) {
|
||||
auto comments = data.deck->deckList.getComments();
|
||||
return comments.contains(value, Qt::CaseInsensitive);
|
||||
};
|
||||
};
|
||||
|
||||
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||
auto name = std::any_cast<QString>(sv[0]);
|
||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||
return deck->getDisplayName().contains(name, Qt::CaseInsensitive);
|
||||
};
|
||||
return [=](const DeckSearchData &data) { return data.displayName.contains(name, Qt::CaseInsensitive); };
|
||||
};
|
||||
}
|
||||
|
||||
DeckFilterString::DeckFilterString()
|
||||
{
|
||||
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
|
||||
filter = [](const DeckSearchData &) { return false; };
|
||||
_error = "Not initialized";
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +195,7 @@ DeckFilterString::DeckFilterString(const QString &expr)
|
|||
_error = QString();
|
||||
|
||||
if (ba.isEmpty()) {
|
||||
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return true; };
|
||||
filter = [](const DeckSearchData &) { return true; };
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -215,6 +205,6 @@ DeckFilterString::DeckFilterString(const QString &expr)
|
|||
|
||||
if (!search.parse(ba.data(), filter)) {
|
||||
qCInfo(DeckFilterStringLog).nospace() << "DeckFilterString error for " << expr << "; " << qPrintable(_error);
|
||||
filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; };
|
||||
filter = [](const DeckSearchData &) { return false; };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef DECK_FILTER_STRING_H
|
||||
#define DECK_FILTER_STRING_H
|
||||
|
||||
#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h"
|
||||
#include "../interface/deck_loader/loaded_deck.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QString>
|
||||
|
|
@ -16,26 +16,29 @@
|
|||
inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string");
|
||||
|
||||
/**
|
||||
* Extra info relevant to filtering that isn't present in the DeckPreviewWidget
|
||||
* The data a deck search expression is evaluated against.
|
||||
*
|
||||
* This is a data view rather than a widget pointer, so the same filter
|
||||
* expression can be evaluated against a model or a live widget.
|
||||
*/
|
||||
struct ExtraDeckSearchInfo
|
||||
struct DeckSearchData
|
||||
{
|
||||
/**
|
||||
* The relative filepath starting from the deck folder
|
||||
*/
|
||||
QString relativeFilePath;
|
||||
const LoadedDeck *deck = nullptr; ///< The loaded deck. Must not be null.
|
||||
QString filePath; ///< Absolute path of the deck file.
|
||||
QString displayName; ///< Deck name, or the file name if the deck has no name.
|
||||
QString relativeFilePath; ///< File path relative to the deck folder.
|
||||
};
|
||||
|
||||
typedef std::function<bool(const DeckPreviewWidget *, const ExtraDeckSearchInfo &)> DeckFilter;
|
||||
typedef std::function<bool(const DeckSearchData &data)> DeckFilter;
|
||||
|
||||
class DeckFilterString
|
||||
{
|
||||
public:
|
||||
DeckFilterString();
|
||||
explicit DeckFilterString(const QString &expr);
|
||||
bool check(const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) const
|
||||
bool check(const DeckSearchData &data) const
|
||||
{
|
||||
return filter(deck, info);
|
||||
return filter(data);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ AbstractCounter::AbstractCounter(CounterState *state,
|
|||
{
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
|
||||
connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
|
||||
value = newValue;
|
||||
onValueChanged(oldValue, newValue);
|
||||
update();
|
||||
});
|
||||
|
||||
|
|
@ -228,3 +229,9 @@ void AbstractCounterDialog::changeValue(int diff)
|
|||
curValue += diff;
|
||||
setTextValue(QString::number(curValue));
|
||||
}
|
||||
|
||||
void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/)
|
||||
{
|
||||
// Default: no feedback. Subclasses such as PlayerCounter override this to
|
||||
// flash the counter on meaningful changes (life gain/loss).
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@ protected:
|
|||
bool hovered = false;
|
||||
bool useNameForShortcut;
|
||||
|
||||
/**
|
||||
* @brief Hook for subclasses that need per-value-change feedback (e.g. life-total flash).
|
||||
*
|
||||
* Called whenever the counter's value changes, before the item repaints.
|
||||
*/
|
||||
virtual void onValueChanged(int oldValue, int newValue);
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
|
|
|
|||
|
|
@ -188,6 +188,11 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
|||
AbstractCounter *widget;
|
||||
if (state->getName() == "life") {
|
||||
widget = playerTarget->addCounter(state);
|
||||
connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
|
||||
if (newValue < oldValue) {
|
||||
tableZoneGraphicsItem->triggerDamageShimmer();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
widget = new GeneralCounter(state, player, true, this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#include "player_target.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../game_scene.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPixmapCache>
|
||||
|
|
@ -21,17 +24,24 @@ QRectF PlayerCounter::boundingRect() const
|
|||
|
||||
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
const int radius = 8;
|
||||
const qreal border = 1;
|
||||
QPainterPath path(QPointF(50 - border / 2, border / 2));
|
||||
path.lineTo(radius, border / 2);
|
||||
path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90);
|
||||
path.lineTo(border / 2, 30 - border / 2);
|
||||
path.lineTo(50 - border / 2, 30 - border / 2);
|
||||
path.closeSubpath();
|
||||
const int radius = 15;
|
||||
const qreal border = 1.5;
|
||||
// The box is drawn with a border-wide stroke straddling the path, so the
|
||||
// visible outline spans [inset, inset + border]. Fills that must not cover
|
||||
// the outline (e.g. the life-change flash) use a path inset by `border`.
|
||||
const auto makePath = [](qreal inset) {
|
||||
QPainterPath path(QPointF(50 - inset, inset));
|
||||
path.lineTo(radius, inset);
|
||||
path.arcTo(inset, inset, 2 * radius, 2 * radius, 90, 90);
|
||||
path.lineTo(inset, 30 - inset);
|
||||
path.lineTo(50 - inset, 30 - inset);
|
||||
path.closeSubpath();
|
||||
return path;
|
||||
};
|
||||
QPainterPath path = makePath(border / 2);
|
||||
|
||||
QPen pen(QColor(100, 100, 100));
|
||||
pen.setWidth(border);
|
||||
pen.setWidthF(border);
|
||||
painter->setPen(pen);
|
||||
painter->setBrush(hovered ? QColor(50, 50, 50, 160) : QColor(0, 0, 0, 160));
|
||||
|
||||
|
|
@ -45,6 +55,48 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
|
|||
painter->setFont(font);
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value));
|
||||
|
||||
// Life-change flash: emerald on gain, red on loss, decaying over a few ticks.
|
||||
if (flashAlpha > 0) {
|
||||
painter->save();
|
||||
QColor flashColor = flashDelta > 0 ? QColor(52, 224, 122) : QColor(239, 68, 68);
|
||||
flashColor.setAlphaF(0.45 * flashAlpha);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(flashColor);
|
||||
painter->setOpacity(0.85);
|
||||
painter->drawPath(makePath(border));
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerCounter::onValueChanged(int oldValue, int newValue)
|
||||
{
|
||||
flashDelta = newValue - oldValue;
|
||||
if (flashDelta == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SettingsCache::instance().userInterface().getLifeCounterAnimationsEnabled()) {
|
||||
flashAlpha = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
flashAlpha = 1.0;
|
||||
flashClock.start();
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->registerAnimationItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerCounter::animationEvent()
|
||||
{
|
||||
flashAlpha = 1.0 - flashClock.elapsed() / flashDurationMs;
|
||||
if (flashAlpha <= 0.0) {
|
||||
flashAlpha = 0.0;
|
||||
return false;
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerTarget::PlayerTarget(PlayerLogic *_owner, QGraphicsItem *parentItem)
|
||||
|
|
|
|||
|
|
@ -7,21 +7,34 @@
|
|||
#ifndef PLAYERTARGET_H
|
||||
#define PLAYERTARGET_H
|
||||
|
||||
#include "../animated_item.h"
|
||||
#include "../board/abstract_counter.h"
|
||||
#include "../board/arrow_target.h"
|
||||
#include "../board/graphics_item_type.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QPixmap>
|
||||
|
||||
class PlayerLogic;
|
||||
|
||||
class PlayerCounter : public AbstractCounter
|
||||
class PlayerCounter : public AbstractCounter, public IAnimatedItem
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
void onValueChanged(int oldValue, int newValue) override;
|
||||
|
||||
private:
|
||||
static constexpr qreal flashDurationMs = 450.0;
|
||||
|
||||
QElapsedTimer flashClock;
|
||||
qreal flashAlpha = 0.0;
|
||||
int flashDelta = 0;
|
||||
|
||||
public:
|
||||
PlayerCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent);
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
bool animationEvent() override;
|
||||
};
|
||||
|
||||
class PlayerTarget : public ArrowTarget
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "../board/arrow_item.h"
|
||||
#include "../board/card_drag_item.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../game_scene.h"
|
||||
#include "../z_values.h"
|
||||
|
||||
#include <QGraphicsScene>
|
||||
|
|
@ -47,6 +48,31 @@ void TableZone::updateBg()
|
|||
update();
|
||||
}
|
||||
|
||||
void TableZone::triggerDamageShimmer()
|
||||
{
|
||||
if (!SettingsCache::instance().userInterface().getBattlefieldFlashEnabled()) {
|
||||
damageShimmerAlpha = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
damageShimmerAlpha = 1.0;
|
||||
shimmerClock.start();
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->registerAnimationItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool TableZone::animationEvent()
|
||||
{
|
||||
damageShimmerAlpha = 1.0 - shimmerClock.elapsed() / shimmerDurationMs;
|
||||
if (damageShimmerAlpha <= 0.0) {
|
||||
damageShimmerAlpha = 0.0;
|
||||
return false;
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
|
||||
QRectF TableZone::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, width, height);
|
||||
|
|
@ -77,6 +103,13 @@ void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
|
|||
painter->fillRect(boundingRect(), FADE_MASK);
|
||||
}
|
||||
|
||||
// Decaying crimson wash from taking damage.
|
||||
if (damageShimmerAlpha > 0.0) {
|
||||
QColor shimmerColor(239, 68, 68);
|
||||
shimmerColor.setAlphaF(0.22 * damageShimmerAlpha);
|
||||
painter->fillRect(boundingRect(), shimmerColor);
|
||||
}
|
||||
|
||||
paintLandDivider(painter);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,16 +8,19 @@
|
|||
#define TABLEZONE_H
|
||||
|
||||
#include "../../game/zones/table_zone_logic.h"
|
||||
#include "../animated_item.h"
|
||||
#include "../board/abstract_card_item.h"
|
||||
#include "select_zone.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
/**
|
||||
* @brief TableZone is the grid based rect where CardItems may be placed.
|
||||
*
|
||||
* It is the main play zone and can be customized with background images.
|
||||
*/
|
||||
//! \todo Refactor methods to make more readable, extract logic to private methods (especially reorganizeCards()).
|
||||
class TableZone : public SelectZone
|
||||
class TableZone : public SelectZone, public IAnimatedItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -121,6 +124,16 @@ public:
|
|||
*/
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
/**
|
||||
Flashes the table surface after a player loses life.
|
||||
|
||||
Wired up through the life counter so the battlefield glows when life drops.
|
||||
*/
|
||||
void triggerDamageShimmer();
|
||||
|
||||
/** @brief Decays the damage shimmer by one timer tick. */
|
||||
bool animationEvent() override;
|
||||
|
||||
/**
|
||||
Toggles the selected items as tapped.
|
||||
*/
|
||||
|
|
@ -185,6 +198,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
static constexpr qreal shimmerDurationMs = 450.0;
|
||||
|
||||
QElapsedTimer shimmerClock;
|
||||
qreal damageShimmerAlpha = 0.0;
|
||||
|
||||
void paintZoneOutline(QPainter *painter);
|
||||
void paintLandDivider(QPainter *painter);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,16 +57,16 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
|||
gameNameFilterEdit->setText(filters.gameNameFilter);
|
||||
auto *gameNameFilterLabel = new QLabel(tr("Game &description:"));
|
||||
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
|
||||
creatorNameFilterEdit = new QLineEdit;
|
||||
creatorNameFilterEdit->setText(filters.creatorNameFilters.join(", "));
|
||||
auto *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
|
||||
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
|
||||
hostNameFilterEdit = new QLineEdit;
|
||||
hostNameFilterEdit->setText(filters.hostNameFilters.join(", "));
|
||||
auto *hostNameFilterLabel = new QLabel(tr("&Host name:"));
|
||||
hostNameFilterLabel->setBuddy(hostNameFilterEdit);
|
||||
|
||||
auto *generalGrid = new QGridLayout;
|
||||
generalGrid->addWidget(gameNameFilterLabel, 0, 0);
|
||||
generalGrid->addWidget(gameNameFilterEdit, 0, 1);
|
||||
generalGrid->addWidget(creatorNameFilterLabel, 1, 0);
|
||||
generalGrid->addWidget(creatorNameFilterEdit, 1, 1);
|
||||
generalGrid->addWidget(hostNameFilterLabel, 1, 0);
|
||||
generalGrid->addWidget(hostNameFilterEdit, 1, 1);
|
||||
generalGrid->addWidget(maxGameAgeLabel, 2, 0);
|
||||
generalGrid->addWidget(maxGameAgeComboBox, 2, 1);
|
||||
generalGroupBox = new QGroupBox(tr("General"));
|
||||
|
|
@ -193,7 +193,7 @@ GameFilterConfigs DlgFilterGames::getFilters() const
|
|||
hideNotBuddyCreatedGames->isChecked(),
|
||||
hideOpenDecklistGames->isChecked(),
|
||||
gameNameFilterEdit->text(),
|
||||
getCreatorNameFilters(),
|
||||
getHostNameFilters(),
|
||||
getGameTypeFilter(),
|
||||
maxPlayersFilterMinSpinBox->value(),
|
||||
maxPlayersFilterMaxSpinBox->value(),
|
||||
|
|
@ -216,9 +216,9 @@ void DlgFilterGames::toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled)
|
|||
showOnlyIfSpectatorsCanSeeHands->setDisabled(!spectatorsEnabled);
|
||||
}
|
||||
|
||||
QStringList DlgFilterGames::getCreatorNameFilters() const
|
||||
QStringList DlgFilterGames::getHostNameFilters() const
|
||||
{
|
||||
return creatorNameFilterEdit->text().split(",", Qt::SkipEmptyParts);
|
||||
return hostNameFilterEdit->text().split(",", Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
QSet<int> DlgFilterGames::getGameTypeFilter() const
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ private:
|
|||
QCheckBox *hideNotBuddyCreatedGames;
|
||||
QCheckBox *hideOpenDecklistGames;
|
||||
QLineEdit *gameNameFilterEdit;
|
||||
QLineEdit *creatorNameFilterEdit;
|
||||
QLineEdit *hostNameFilterEdit;
|
||||
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
|
||||
QSpinBox *maxPlayersFilterMinSpinBox;
|
||||
QSpinBox *maxPlayersFilterMaxSpinBox;
|
||||
|
|
@ -50,7 +50,7 @@ private:
|
|||
const GamesProxyModel *gamesProxyModel;
|
||||
const QMap<QTime, QString> gameAgeMap;
|
||||
|
||||
[[nodiscard]] QStringList getCreatorNameFilters() const;
|
||||
[[nodiscard]] QStringList getHostNameFilters() const;
|
||||
[[nodiscard]] QSet<int> getGameTypeFilter() const;
|
||||
[[nodiscard]] QTime getMaxGameAge() const;
|
||||
[[nodiscard]] bool getShowSpectatorPasswordProtected() const;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct GameFilterConfigs
|
|||
bool hideNotBuddyCreatedGames = false;
|
||||
bool hideOpenDecklistGames = false;
|
||||
QString gameNameFilter = "";
|
||||
QStringList creatorNameFilters = {};
|
||||
QStringList hostNameFilters = {};
|
||||
QSet<int> gameTypeFilter = {};
|
||||
int maxPlayersFilterMin = DEFAULT_MAX_PLAYERS_MIN;
|
||||
int maxPlayersFilterMax = DEFAULT_MAX_PLAYERS_MAX;
|
||||
|
|
|
|||
|
|
@ -17,13 +17,27 @@ enum GameListColumn
|
|||
ROOM,
|
||||
CREATED,
|
||||
DESCRIPTION,
|
||||
CREATOR,
|
||||
HOST,
|
||||
GAME_TYPE,
|
||||
RESTRICTIONS,
|
||||
PLAYERS,
|
||||
SPECTATORS
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @brief Returns the user info of the game's current host, falling back to the creator.
|
||||
*
|
||||
* The server only sends host_info once a host transfer has happened, so older
|
||||
* servers and freshly created games fall back to the original creator.
|
||||
*/
|
||||
const ServerInfo_User &getGameHost(const ServerInfo_Game &game)
|
||||
{
|
||||
return game.has_host_info() ? game.host_info() : game.creator_info();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
const QString GamesModel::getGameCreatedString(const int secs)
|
||||
{
|
||||
static const QTime zeroTime{0, 0};
|
||||
|
|
@ -110,16 +124,16 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
|||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case CREATOR: {
|
||||
case HOST: {
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole:
|
||||
return QString::fromStdString(gameentry.creator_info().name());
|
||||
return QString::fromStdString(getGameHost(gameentry).name());
|
||||
case Qt::DecorationRole: {
|
||||
return UserLevelPixmapGenerator::generateIcon(
|
||||
13, UserLevelFlags(gameentry.creator_info().user_level()),
|
||||
gameentry.creator_info().pawn_colors(), false,
|
||||
QString::fromStdString(gameentry.creator_info().privlevel()));
|
||||
const ServerInfo_User &host = getGameHost(gameentry);
|
||||
return UserLevelPixmapGenerator::generateIcon(13, UserLevelFlags(host.user_level()),
|
||||
host.pawn_colors(), false,
|
||||
QString::fromStdString(host.privlevel()));
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
|
|
@ -233,8 +247,8 @@ QVariant GamesModel::headerData(int section, Qt::Orientation /*orientation*/, in
|
|||
}
|
||||
case DESCRIPTION:
|
||||
return tr("Description");
|
||||
case CREATOR:
|
||||
return tr("Creator");
|
||||
case HOST:
|
||||
return tr("Host");
|
||||
case GAME_TYPE:
|
||||
return tr("Type");
|
||||
case RESTRICTIONS:
|
||||
|
|
@ -347,7 +361,7 @@ void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameType
|
|||
gameFilters.isHideFullGames(), gameFilters.isHideGamesThatStarted(),
|
||||
gameFilters.isHidePasswordProtectedGames(), gameFilters.isHideNotBuddyCreatedGames(),
|
||||
gameFilters.isHideOpenDecklistGames(), gameFilters.getGameNameFilter(),
|
||||
gameFilters.getCreatorNameFilters(), newGameTypeFilter, gameFilters.getMinPlayers(),
|
||||
gameFilters.getHostNameFilters(), newGameTypeFilter, gameFilters.getMinPlayers(),
|
||||
gameFilters.getMaxPlayers(), gameFilters.getMaxGameAge(),
|
||||
gameFilters.isShowOnlyIfSpectatorsCanWatch(), gameFilters.isShowSpectatorPasswordProtected(),
|
||||
gameFilters.isShowOnlyIfSpectatorsCanChat(), gameFilters.isShowOnlyIfSpectatorsCanSeeHands()});
|
||||
|
|
@ -364,7 +378,7 @@ void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameType
|
|||
gameFilters.setHideNotBuddyCreatedGames(filters.hideNotBuddyCreatedGames);
|
||||
gameFilters.setHideOpenDecklistGames(filters.hideOpenDecklistGames);
|
||||
gameFilters.setGameNameFilter(filters.gameNameFilter);
|
||||
gameFilters.setCreatorNameFilters(filters.creatorNameFilters);
|
||||
gameFilters.setHostNameFilters(filters.hostNameFilters);
|
||||
|
||||
QMapIterator<int, QString> gameTypeIterator(allGameTypes);
|
||||
while (gameTypeIterator.hasNext()) {
|
||||
|
|
@ -409,11 +423,11 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
|||
return false;
|
||||
}
|
||||
if (filters.hideIgnoredUserGames &&
|
||||
userListProxy->isUserIgnored(QString::fromStdString(game.creator_info().name()))) {
|
||||
userListProxy->isUserIgnored(QString::fromStdString(getGameHost(game).name()))) {
|
||||
return false;
|
||||
}
|
||||
if (filters.hideNotBuddyCreatedGames &&
|
||||
!userListProxy->isUserBuddy(QString::fromStdString(game.creator_info().name()))) {
|
||||
!userListProxy->isUserBuddy(QString::fromStdString(getGameHost(game).name()))) {
|
||||
return false;
|
||||
}
|
||||
if (filters.hideFullGames && game.player_count() == game.max_players()) {
|
||||
|
|
@ -435,10 +449,10 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (!filters.creatorNameFilters.isEmpty()) {
|
||||
if (!filters.hostNameFilters.isEmpty()) {
|
||||
bool found = false;
|
||||
for (const auto &createNameFilter : filters.creatorNameFilters) {
|
||||
if (QString::fromStdString(game.creator_info().name()).contains(createNameFilter, Qt::CaseInsensitive)) {
|
||||
for (const auto &hostNameFilter : filters.hostNameFilters) {
|
||||
if (QString::fromStdString(getGameHost(game).name()).contains(hostNameFilter, Qt::CaseInsensitive)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,15 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
|||
connect(&tapAnimationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().cardsDisplay(),
|
||||
&CardsDisplaySettings::setTapAnimation);
|
||||
|
||||
lifeCounterAnimationsCheckBox.setChecked(
|
||||
SettingsCache::instance().userInterface().getLifeCounterAnimationsEnabled());
|
||||
connect(&lifeCounterAnimationsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setLifeCounterAnimationsEnabled);
|
||||
|
||||
battlefieldFlashCheckBox.setChecked(SettingsCache::instance().userInterface().getBattlefieldFlashEnabled());
|
||||
connect(&battlefieldFlashCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setBattlefieldFlashEnabled);
|
||||
|
||||
connect(&enableAllAnimationsButton, &QPushButton::clicked, this, &UserInterfaceSettingsPage::enableAllAnimations);
|
||||
connect(&disableAllAnimationsButton, &QPushButton::clicked, this, &UserInterfaceSettingsPage::disableAllAnimations);
|
||||
|
||||
|
|
@ -123,6 +132,8 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
|||
animationGrid->addWidget(&enableAllAnimationsButton, 0, 0);
|
||||
animationGrid->addWidget(&disableAllAnimationsButton, 0, 1);
|
||||
animationGrid->addWidget(&tapAnimationCheckBox, 1, 0);
|
||||
animationGrid->addWidget(&lifeCounterAnimationsCheckBox, 2, 0);
|
||||
animationGrid->addWidget(&battlefieldFlashCheckBox, 3, 0);
|
||||
|
||||
animationGroupBox = new QGroupBox;
|
||||
animationGroupBox->setLayout(animationGrid);
|
||||
|
|
@ -276,11 +287,15 @@ void UserInterfaceSettingsPage::setNotificationEnabled(QT_STATE_CHANGED_T i)
|
|||
void UserInterfaceSettingsPage::enableAllAnimations()
|
||||
{
|
||||
tapAnimationCheckBox.setChecked(true);
|
||||
lifeCounterAnimationsCheckBox.setChecked(true);
|
||||
battlefieldFlashCheckBox.setChecked(true);
|
||||
}
|
||||
|
||||
void UserInterfaceSettingsPage::disableAllAnimations()
|
||||
{
|
||||
tapAnimationCheckBox.setChecked(false);
|
||||
lifeCounterAnimationsCheckBox.setChecked(false);
|
||||
battlefieldFlashCheckBox.setChecked(false);
|
||||
}
|
||||
|
||||
void UserInterfaceSettingsPage::updateCommanderSpellbookUiState()
|
||||
|
|
@ -328,6 +343,8 @@ void UserInterfaceSettingsPage::retranslateUi()
|
|||
enableAllAnimationsButton.setText(tr("&Enable all animations"));
|
||||
disableAllAnimationsButton.setText(tr("&Disable all animations"));
|
||||
tapAnimationCheckBox.setText(tr("&Tap/untap animation"));
|
||||
lifeCounterAnimationsCheckBox.setText(tr("Life counter flash"));
|
||||
battlefieldFlashCheckBox.setText(tr("Battlefield flash on damage"));
|
||||
deckEditorGroupBox->setTitle(tr("Deck editor/storage settings"));
|
||||
openDeckInNewTabCheckBox.setText(tr("Open deck in new tab by default"));
|
||||
visualDeckStorageInGameCheckBox.setText(tr("Use visual deck storage in game lobby"));
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ private:
|
|||
QPushButton enableAllAnimationsButton;
|
||||
QPushButton disableAllAnimationsButton;
|
||||
QCheckBox tapAnimationCheckBox;
|
||||
QCheckBox lifeCounterAnimationsCheckBox;
|
||||
QCheckBox battlefieldFlashCheckBox;
|
||||
QCheckBox openDeckInNewTabCheckBox;
|
||||
QLabel visualDeckStoragePromptForConversionLabel;
|
||||
QComboBox visualDeckStoragePromptForConversionSelector;
|
||||
|
|
|
|||
|
|
@ -73,10 +73,14 @@ static QString toRelativeFilepath(const QString &filePath)
|
|||
|
||||
void VisualDeckStorageSearchWidget::filterWidgets(QList<DeckPreviewWidget *> widgets, const QString &searchText)
|
||||
{
|
||||
auto filterString = DeckFilterString(searchText);
|
||||
const auto filterString = DeckFilterString(searchText);
|
||||
|
||||
for (auto widget : widgets) {
|
||||
QString relativeFilePath = toRelativeFilepath(widget->filePath);
|
||||
widget->filteredBySearch = !filterString.check(widget, {relativeFilePath});
|
||||
const DeckSearchData searchData{.deck = &widget->deckLoader->getDeck(),
|
||||
.filePath = widget->filePath,
|
||||
.displayName = widget->getDisplayName(),
|
||||
.relativeFilePath = toRelativeFilepath(widget->filePath)};
|
||||
|
||||
widget->filteredBySearch = !filterString.check(searchData);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ public:
|
|||
[[nodiscard]] virtual bool getShowStatusBar() const = 0;
|
||||
[[nodiscard]] virtual bool getShowShortcuts() const = 0;
|
||||
[[nodiscard]] virtual bool getShowGameSelectorFilterToolbar() const = 0;
|
||||
[[nodiscard]] virtual bool getLifeCounterAnimationsEnabled() const = 0;
|
||||
[[nodiscard]] virtual bool getBattlefieldFlashEnabled() const = 0;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTERFACE_INTERFACE_SETTINGS_PROVIDER_H
|
||||
|
|
|
|||
|
|
@ -526,10 +526,7 @@ void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface,
|
|||
|
||||
if (broadcastUpdate) {
|
||||
ServerInfo_Game gameInfo;
|
||||
gameInfo.set_room_id(room->getId());
|
||||
gameInfo.set_game_id(gameId);
|
||||
gameInfo.set_player_count(getPlayerCount());
|
||||
gameInfo.set_spectators_count(getSpectatorCount());
|
||||
getInfo(gameInfo);
|
||||
emit gameInfoChanged(gameInfo);
|
||||
}
|
||||
|
||||
|
|
@ -588,10 +585,7 @@ void Server_Game::removeParticipant(Server_AbstractParticipant *participant, Eve
|
|||
}
|
||||
|
||||
ServerInfo_Game gameInfo;
|
||||
gameInfo.set_room_id(room->getId());
|
||||
gameInfo.set_game_id(gameId);
|
||||
gameInfo.set_player_count(getPlayerCount());
|
||||
gameInfo.set_spectators_count(getSpectatorCount());
|
||||
getInfo(gameInfo);
|
||||
emit gameInfoChanged(gameInfo);
|
||||
}
|
||||
|
||||
|
|
@ -847,6 +841,12 @@ void Server_Game::getInfo(ServerInfo_Game &result) const
|
|||
result.set_player_count(getPlayerCount());
|
||||
result.set_started(gameStarted);
|
||||
result.mutable_creator_info()->CopyFrom(*getCreatorInfo());
|
||||
const Server_AbstractParticipant *host = participants.value(hostId, nullptr);
|
||||
if (host != nullptr) {
|
||||
result.mutable_host_info()->CopyFrom(*host->getUserInfo());
|
||||
} else {
|
||||
result.mutable_host_info()->CopyFrom(*getCreatorInfo());
|
||||
}
|
||||
result.set_only_buddies(onlyBuddies);
|
||||
result.set_only_registered(onlyRegistered);
|
||||
result.set_spectators_allowed(getSpectatorsAllowed());
|
||||
|
|
|
|||
|
|
@ -62,4 +62,7 @@ message ServerInfo_Game {
|
|||
|
||||
// whether the game is closed. Closed games are finished and can't be interacted with
|
||||
optional bool closed = 52;
|
||||
|
||||
// the current host of the game, which may differ from the creator after a host transfer
|
||||
optional ServerInfo_User host_info = 53;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,14 +104,14 @@ QString GameFiltersSettings::getGameNameFilter() const
|
|||
return getValue("gameNameFilter").toString();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setCreatorNameFilters(QStringList creatorName)
|
||||
void GameFiltersSettings::setHostNameFilters(QStringList hostName)
|
||||
{
|
||||
setValue(creatorName, "creatorNameFilter");
|
||||
setValue(hostName, "hostNameFilter");
|
||||
}
|
||||
|
||||
QStringList GameFiltersSettings::getCreatorNameFilters() const
|
||||
QStringList GameFiltersSettings::getHostNameFilters() const
|
||||
{
|
||||
return getValue("creatorNameFilter").toStringList();
|
||||
return getValue("hostNameFilter").toStringList();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setMinPlayers(int min)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public:
|
|||
bool isHideNotBuddyCreatedGames() const;
|
||||
bool isHideOpenDecklistGames() const;
|
||||
QString getGameNameFilter() const;
|
||||
QStringList getCreatorNameFilters() const;
|
||||
QStringList getHostNameFilters() const;
|
||||
int getMinPlayers() const;
|
||||
int getMaxPlayers() const;
|
||||
QTime getMaxGameAge() const;
|
||||
|
|
@ -42,7 +42,7 @@ public:
|
|||
void setHidePasswordProtectedGames(bool hide);
|
||||
void setHideNotBuddyCreatedGames(bool hide);
|
||||
void setGameNameFilter(QString gameName);
|
||||
void setCreatorNameFilters(QStringList creatorName);
|
||||
void setHostNameFilters(QStringList hostName);
|
||||
void setMinPlayers(int min);
|
||||
void setMaxPlayers(int max);
|
||||
void setMaxGameAge(const QTime &maxGameAge);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,16 @@ bool InterfaceSettings::getShowGameSelectorFilterToolbar() const
|
|||
return getValue("showGameSelectorFilterToolbar", QString(), QString(), true).toBool();
|
||||
}
|
||||
|
||||
bool InterfaceSettings::getLifeCounterAnimationsEnabled() const
|
||||
{
|
||||
return getValue("lifeCounterAnimationsEnabled", QString(), QString(), true).toBool();
|
||||
}
|
||||
|
||||
bool InterfaceSettings::getBattlefieldFlashEnabled() const
|
||||
{
|
||||
return getValue("battlefieldFlashEnabled", QString(), QString(), true).toBool();
|
||||
}
|
||||
|
||||
void InterfaceSettings::setUseTearOffMenus(bool _useTearOffMenus)
|
||||
{
|
||||
setValue(_useTearOffMenus, "useTearOffMenus");
|
||||
|
|
@ -326,3 +336,15 @@ void InterfaceSettings::setShowGameSelectorFilterToolbar(bool _showGameSelectorF
|
|||
setValue(_showGameSelectorFilterToolbar, "showGameSelectorFilterToolbar");
|
||||
emit showGameSelectorFilterToolbarChanged(_showGameSelectorFilterToolbar);
|
||||
}
|
||||
|
||||
void InterfaceSettings::setLifeCounterAnimationsEnabled(bool _lifeCounterAnimationsEnabled)
|
||||
{
|
||||
setValue(_lifeCounterAnimationsEnabled, "lifeCounterAnimationsEnabled");
|
||||
emit lifeCounterAnimationsEnabledChanged(_lifeCounterAnimationsEnabled);
|
||||
}
|
||||
|
||||
void InterfaceSettings::setBattlefieldFlashEnabled(bool _battlefieldFlashEnabled)
|
||||
{
|
||||
setValue(_battlefieldFlashEnabled, "battlefieldFlashEnabled");
|
||||
emit battlefieldFlashEnabledChanged(_battlefieldFlashEnabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ public:
|
|||
[[nodiscard]] bool getShowStatusBar() const override;
|
||||
[[nodiscard]] bool getShowShortcuts() const override;
|
||||
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const override;
|
||||
[[nodiscard]] bool getLifeCounterAnimationsEnabled() const override;
|
||||
[[nodiscard]] bool getBattlefieldFlashEnabled() const override;
|
||||
|
||||
void setUseTearOffMenus(bool _useTearOffMenus);
|
||||
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
||||
|
|
@ -74,6 +76,8 @@ public:
|
|||
void setShowStatusBar(bool _showStatusBar);
|
||||
void setShowShortcuts(bool _showShortcuts);
|
||||
void setShowGameSelectorFilterToolbar(bool _showGameSelectorFilterToolbar);
|
||||
void setLifeCounterAnimationsEnabled(bool _lifeCounterAnimationsEnabled);
|
||||
void setBattlefieldFlashEnabled(bool _battlefieldFlashEnabled);
|
||||
|
||||
signals:
|
||||
void useTearOffMenusChanged(bool state);
|
||||
|
|
@ -85,6 +89,8 @@ signals:
|
|||
void tallyTypeChanged(int type);
|
||||
void showStatusBarChanged(bool state);
|
||||
void showGameSelectorFilterToolbarChanged(bool state);
|
||||
void lifeCounterAnimationsEnabledChanged(bool state);
|
||||
void battlefieldFlashEnabledChanged(bool state);
|
||||
|
||||
public:
|
||||
explicit InterfaceSettings(const QString &settingPath, QObject *parent = nullptr);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue