mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-25 11:56:11 -07:00
Compare commits
8 commits
3b1d808c73
...
f7263e1287
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7263e1287 | ||
|
|
b6e74928d4 | ||
|
|
64e5c0de19 | ||
|
|
81c9edbf89 | ||
|
|
bd1fb69800 | ||
|
|
770282c5b5 | ||
|
|
b16497327f | ||
|
|
23bdc1d986 |
38 changed files with 216 additions and 359 deletions
|
|
@ -8,7 +8,6 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
|
|||
gtest \
|
||||
mariadb-libs \
|
||||
ninja \
|
||||
openssl \
|
||||
protobuf \
|
||||
qt6-base \
|
||||
qt6-declarative \
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ RUN apt-get update && \
|
|||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ RUN apt-get update && \
|
|||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ RUN dnf install -y \
|
|||
git \
|
||||
mariadb-devel \
|
||||
ninja-build \
|
||||
openssl-devel \
|
||||
protobuf-devel \
|
||||
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||
qt6-qtimageformats \
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ RUN dnf install -y \
|
|||
git \
|
||||
mariadb-devel \
|
||||
ninja-build \
|
||||
openssl-devel \
|
||||
protobuf-devel \
|
||||
qt6-{qtdeclarative,qtshadertools,qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||
qt6-qtimageformats \
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ RUN apt-get update && \
|
|||
libmariadb-dev-compat \
|
||||
libprotobuf-dev \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-tools-dev \
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ RUN apt-get update && \
|
|||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ RUN apt-get update && \
|
|||
libprotobuf-dev \
|
||||
libqt6multimedia6 \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
ninja-build \
|
||||
protobuf-compiler \
|
||||
qt6-image-formats-plugins \
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
# This file sets all the variables shared between the projects
|
||||
# like the installation path, compilation flags etc..
|
||||
|
||||
# 3.16 required for Qt6 and target_precompile_headers()
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
# cmake 3.16 is required if using qt6
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Use compiler cache (ccache)
|
||||
option(USE_CCACHE "Cache the build results with ccache" OFF)
|
||||
|
|
@ -184,9 +184,6 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
|||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Reduce compiler I/O by using pipes between stages instead of temp files
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
||||
else()
|
||||
# other: osx/llvm, bsd/llvm
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
||||
|
|
@ -195,9 +192,6 @@ else()
|
|||
else()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
|
||||
endif()
|
||||
|
||||
# Reduce compiler I/O by using pipes between stages instead of temp files
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
||||
endif()
|
||||
|
||||
# GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
|
||||
|
|
@ -245,6 +239,11 @@ if(WIN32)
|
|||
find_package(OpenSSL REQUIRED)
|
||||
if(OPENSSL_FOUND)
|
||||
include_directories(${OPENSSL_INCLUDE_DIRS})
|
||||
else()
|
||||
message(
|
||||
WARNING
|
||||
"Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ RUN apt-get update \
|
|||
libmariadb-dev-compat \
|
||||
libprotobuf-dev \
|
||||
libqt6sql6-mysql \
|
||||
libssl-dev \
|
||||
qt6-websockets-dev \
|
||||
protobuf-compiler \
|
||||
qt6-tools-dev \
|
||||
|
|
@ -43,7 +42,6 @@ RUN apt-get update \
|
|||
libprotobuf32t64 \
|
||||
libqt6sql6-mysql \
|
||||
libqt6websockets6 \
|
||||
libssl3 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
|
|
|||
|
|
@ -44,16 +44,11 @@ GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent)
|
|||
|
||||
GameScene::~GameScene()
|
||||
{
|
||||
// Sever all destroyed->removeAnimatedItem connections before the members below
|
||||
// are destroyed: the base QGraphicsScene destructor destroys the remaining items,
|
||||
// and their destroyed() signals must not reach slots that reference members that
|
||||
// no longer exist. The connection handle overload is used because the string-based
|
||||
// disconnect(nullptr, nullptr, this, nullptr) is invalid (the sender must never be
|
||||
// nullptr) and would otherwise fail to sever these pointer-to-member connections.
|
||||
for (auto it = animationItemConnections.constBegin(); it != animationItemConnections.constEnd(); ++it) {
|
||||
QObject::disconnect(*it);
|
||||
}
|
||||
animationItemConnections.clear();
|
||||
// Sever all incoming connections (animated item destroy-tracking) before the
|
||||
// members below are destroyed: the base QGraphicsScene destructor destroys the
|
||||
// remaining items, and their destroyed() signals must not reach slots that
|
||||
// reference members that no longer exist.
|
||||
QObject::disconnect(nullptr, nullptr, this, nullptr);
|
||||
|
||||
delete animationTimer;
|
||||
animationTimer = nullptr;
|
||||
|
|
@ -782,15 +777,8 @@ void GameScene::registerAnimationItem(IAnimatedItem *item)
|
|||
if (!object) {
|
||||
return;
|
||||
}
|
||||
// Guard against duplicate connections using the connection map, not
|
||||
// animatedItems: the animation timer removes entries from animatedItems when an
|
||||
// animation completes, but the destroyed->removeAnimatedItem connection must
|
||||
// persist until the object is destroyed. Relying on animatedItems here would let
|
||||
// a re-registered item (e.g. a life counter that flashes repeatedly) accumulate
|
||||
// duplicate destroyed connections, the older ones of which would survive teardown.
|
||||
if (!animationItemConnections.contains(object)) {
|
||||
animationItemConnections.insert(object,
|
||||
connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem));
|
||||
if (!animatedItems.contains(object)) {
|
||||
connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem);
|
||||
}
|
||||
animatedItems.insert(object, item);
|
||||
if (animationTimer && !animationTimer->isActive()) {
|
||||
|
|
@ -809,7 +797,6 @@ void GameScene::unregisterAnimationItem(IAnimatedItem *item)
|
|||
void GameScene::removeAnimatedItem(QObject *item)
|
||||
{
|
||||
animatedItems.remove(item);
|
||||
animationItemConnections.remove(item);
|
||||
if (animationTimer && animatedItems.isEmpty()) {
|
||||
animationTimer->stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,11 +54,9 @@ private:
|
|||
QPointer<CardItem> hoveredCard; ///< Currently hovered card
|
||||
QBasicTimer *animationTimer; ///< Timer for scene animations
|
||||
QHash<QObject *, IAnimatedItem *> animatedItems; ///< Items currently animating
|
||||
QHash<QObject *, QMetaObject::Connection>
|
||||
animationItemConnections; ///< destroyed->removeAnimatedItem handles per animated item
|
||||
int playerRotation; ///< Rotation offset for player layout
|
||||
bool rearranging = false; ///< Guard against re-entrant rearrange
|
||||
bool needsReArrange = false; ///< Pending rearrange requested during a pass
|
||||
int playerRotation; ///< Rotation offset for player layout
|
||||
bool rearranging = false; ///< Guard against re-entrant rearrange
|
||||
bool needsReArrange = false; ///< Pending rearrange requested during a pass
|
||||
|
||||
/**
|
||||
* @brief Updates which card is currently hovered based on scene coordinates.
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ void HandZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
bool sameZone = startZone == getLogic();
|
||||
x = calcDropIndexFromY(dropPoint.y(), !sameZone);
|
||||
x = calcDropIndexFromY(dropPoint.y());
|
||||
}
|
||||
|
||||
Command_MoveCard cmd;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ SelectZone::StackLayoutParams SelectZone::buildStackParams(qreal minOffset) cons
|
|||
return {cardCount, boundingRect().height(), cardHeight, offset, minOffset};
|
||||
}
|
||||
|
||||
int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset) const
|
||||
int SelectZone::calcDropIndexFromY(qreal dropY, qreal minOffset) const
|
||||
{
|
||||
const auto &cards = getLogic()->getCards();
|
||||
if (cards.isEmpty()) {
|
||||
|
|
@ -94,8 +94,7 @@ int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal min
|
|||
if (effectiveOffset <= 0.0) {
|
||||
return 0;
|
||||
}
|
||||
int max = allowCountExpand ? params.cardCount : params.cardCount - 1;
|
||||
return qBound(0, qRound((dropY - start) / effectiveOffset), max);
|
||||
return qBound(0, qRound((dropY - start) / effectiveOffset), params.cardCount - 1);
|
||||
}
|
||||
|
||||
void SelectZone::restoreStaleEscapedCards()
|
||||
|
|
|
|||
|
|
@ -104,12 +104,8 @@ protected:
|
|||
/**
|
||||
* @brief Computes the card index at a given y-coordinate within the zone's vertical layout.
|
||||
* Returns 0 if the zone has no cards or the offset is zero.
|
||||
*
|
||||
* @param dropY The y-coordinate that the card was dropped at
|
||||
* @param allowCountExpand If false, clamps the index at the number of cards minus 1
|
||||
* @param minOffset Minimum offset to preserve
|
||||
*/
|
||||
int calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset = 0.0) const;
|
||||
int calcDropIndexFromY(qreal dropY, qreal minOffset = 0.0) const;
|
||||
|
||||
/**
|
||||
* @brief Positions cards vertically with alternating left/right x-offsets.
|
||||
|
|
|
|||
|
|
@ -57,14 +57,18 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
|||
return;
|
||||
}
|
||||
|
||||
bool sameZone = startZone == getLogic();
|
||||
int index = calcDropIndexFromY(dropPoint.y(), !sameZone, MIN_CARD_VISIBLE);
|
||||
if (sameZone) {
|
||||
const auto &cards = getLogic()->getCards();
|
||||
int index;
|
||||
if (startZone == getLogic()) {
|
||||
// Reordering within the zone: use drop position
|
||||
index = calcDropIndexFromY(dropPoint.y(), MIN_CARD_VISIBLE);
|
||||
// Same-zone no-op: don't move a card onto itself
|
||||
const auto &cards = getLogic()->getCards();
|
||||
if (!cards.isEmpty() && cards.at(index)->getId() == dragItems.at(0)->getId()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Coming from another zone: append at end (top of stack, rendered on top)
|
||||
index = static_cast<int>(cards.size());
|
||||
}
|
||||
|
||||
Command_MoveCard cmd;
|
||||
|
|
|
|||
|
|
@ -154,48 +154,6 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
homeTabGroupBox = new QGroupBox;
|
||||
homeTabGroupBox->setLayout(homeTabGrid);
|
||||
|
||||
// Playmat settings
|
||||
playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll);
|
||||
playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly);
|
||||
playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone);
|
||||
int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility());
|
||||
if (visIdx >= 0) {
|
||||
playmatVisibilityCombo.setCurrentIndex(visIdx);
|
||||
}
|
||||
connect(&playmatVisibilityCombo, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt());
|
||||
});
|
||||
playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
|
||||
|
||||
// Playmat mode: Override / Fallback / Deck-only
|
||||
playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck);
|
||||
playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback);
|
||||
playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly);
|
||||
int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode());
|
||||
if (modeIdx >= 0) {
|
||||
playmatModeCombo.setCurrentIndex(modeIdx);
|
||||
}
|
||||
connect(&playmatModeCombo, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt());
|
||||
});
|
||||
playmatModeLabel.setBuddy(&playmatModeCombo);
|
||||
|
||||
// User-level playmat settings: fallback collection.
|
||||
connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
|
||||
&AppearanceSettingsPage::openPlaymatCollectionDialog);
|
||||
|
||||
auto *playmatGrid = new QGridLayout;
|
||||
playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
|
||||
playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1);
|
||||
playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
|
||||
|
||||
playmatGroupBox = new QGroupBox;
|
||||
playmatGroupBox->setLayout(playmatGrid);
|
||||
|
||||
// Styling settings
|
||||
styleUserListCheckBox.setChecked(settings.appearance().getStyleUserList());
|
||||
connect(&styleUserListCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings.appearance(),
|
||||
&AppearanceSettings::setStyleUserList);
|
||||
|
|
@ -301,6 +259,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
cardLayoutGroupBox->setLayout(cardLayoutGrid);
|
||||
|
||||
// Card counter colors
|
||||
|
||||
auto *cardCounterColorsLayout = new QGridLayout;
|
||||
cardCounterColorsLayout->setColumnStretch(1, 1);
|
||||
cardCounterColorsLayout->setColumnStretch(3, 1);
|
||||
|
|
@ -380,6 +339,47 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
tableGroupBox = new QGroupBox;
|
||||
tableGroupBox->setLayout(tableGrid);
|
||||
|
||||
// Playmat settings
|
||||
playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll);
|
||||
playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly);
|
||||
playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone);
|
||||
int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility());
|
||||
if (visIdx >= 0) {
|
||||
playmatVisibilityCombo.setCurrentIndex(visIdx);
|
||||
}
|
||||
connect(&playmatVisibilityCombo, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt());
|
||||
});
|
||||
playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo);
|
||||
|
||||
// Playmat mode: Override / Fallback / Deck-only
|
||||
playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck);
|
||||
playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback);
|
||||
playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly);
|
||||
int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode());
|
||||
if (modeIdx >= 0) {
|
||||
playmatModeCombo.setCurrentIndex(modeIdx);
|
||||
}
|
||||
connect(&playmatModeCombo, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt());
|
||||
});
|
||||
playmatModeLabel.setBuddy(&playmatModeCombo);
|
||||
|
||||
// User-level playmat settings: fallback collection.
|
||||
connect(&playmatDefaultEditButton, &QPushButton::clicked, this,
|
||||
&AppearanceSettingsPage::openPlaymatCollectionDialog);
|
||||
|
||||
auto *playmatGrid = new QGridLayout;
|
||||
playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1);
|
||||
playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1);
|
||||
playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1);
|
||||
playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1);
|
||||
|
||||
playmatGroupBox = new QGroupBox;
|
||||
playmatGroupBox->setLayout(playmatGrid);
|
||||
|
||||
// putting it all together
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(themeGroupBox);
|
||||
|
|
@ -512,12 +512,6 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
homeTabButtonColorSourceBox.setToolTip(
|
||||
tr("Automatic: extract from background if present, otherwise use theme default"));
|
||||
|
||||
playmatGroupBox->setTitle(tr("Playmat settings"));
|
||||
playmatVisibilityLabel.setText(tr("Playmat visibility:"));
|
||||
playmatModeLabel.setText(tr("Default collection behavior:"));
|
||||
playmatDefaultLabel.setText(tr("Default playmat collection:"));
|
||||
playmatDefaultEditButton.setText(tr("Edit..."));
|
||||
|
||||
stylingGroupBox->setTitle(tr("Styling settings"));
|
||||
styleUserListCheckBox.setText(tr("Style user list"));
|
||||
|
||||
|
|
@ -560,4 +554,9 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
tableGroupBox->setTitle(tr("Table grid layout"));
|
||||
invertVerticalCoordinateCheckBox.setText(tr("Invert vertical coordinate"));
|
||||
minPlayersForMultiColumnLayoutLabel.setText(tr("Minimum player count for multi-column layout:"));
|
||||
playmatGroupBox->setTitle(tr("Playmat settings"));
|
||||
playmatVisibilityLabel.setText(tr("Playmat visibility:"));
|
||||
playmatModeLabel.setText(tr("Default collection behavior:"));
|
||||
playmatDefaultLabel.setText(tr("Default playmat collection:"));
|
||||
playmatDefaultEditButton.setText(tr("Edit..."));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,55 +44,46 @@ private:
|
|||
QLabel homeTabButtonColorSourceLabel;
|
||||
QComboBox homeTabButtonColorSourceBox;
|
||||
|
||||
QLabel playmatVisibilityLabel;
|
||||
QComboBox playmatVisibilityCombo;
|
||||
QLabel playmatModeLabel;
|
||||
QComboBox playmatModeCombo;
|
||||
QLabel playmatDefaultLabel;
|
||||
QPushButton playmatDefaultEditButton;
|
||||
|
||||
QCheckBox styleUserListCheckBox;
|
||||
|
||||
QCheckBox showShortcutsCheckBox;
|
||||
QCheckBox showGameSelectorFilterToolbarCheckBox;
|
||||
|
||||
QLabel minPlayersForMultiColumnLayoutLabel;
|
||||
QLabel maxFontSizeForCardsLabel;
|
||||
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
|
||||
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
|
||||
|
||||
QCheckBox displayCardNamesCheckBox;
|
||||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||
QCheckBox cardScalingCheckBox;
|
||||
QCheckBox roundCardCornersCheckBox;
|
||||
QLabel maxFontSizeForCardsLabel;
|
||||
QSpinBox maxFontSizeForCardsEdit;
|
||||
|
||||
QLabel verticalCardOverlapPercentLabel;
|
||||
QSpinBox verticalCardOverlapPercentBox;
|
||||
QLabel cardViewInitialRowsMaxLabel;
|
||||
QSpinBox cardViewInitialRowsMaxBox;
|
||||
QLabel cardViewExpandedRowsMaxLabel;
|
||||
QSpinBox cardViewExpandedRowsMaxBox;
|
||||
|
||||
QList<QLabel *> cardCounterNames;
|
||||
|
||||
QCheckBox horizontalHandCheckBox;
|
||||
QCheckBox leftJustifiedHandCheckBox;
|
||||
|
||||
QCheckBox invertVerticalCoordinateCheckBox;
|
||||
QLabel minPlayersForMultiColumnLayoutLabel;
|
||||
QSpinBox minPlayersForMultiColumnLayoutEdit;
|
||||
|
||||
QLabel playmatVisibilityLabel;
|
||||
QComboBox playmatVisibilityCombo;
|
||||
QLabel playmatModeLabel;
|
||||
QComboBox playmatModeCombo;
|
||||
QLabel playmatDefaultLabel;
|
||||
QPushButton playmatDefaultEditButton;
|
||||
QGroupBox *themeGroupBox;
|
||||
QGroupBox *homeTabGroupBox;
|
||||
QGroupBox *playmatGroupBox;
|
||||
QGroupBox *stylingGroupBox;
|
||||
QGroupBox *menuGroupBox;
|
||||
QGroupBox *printingsGroupBox;
|
||||
QGroupBox *cardsGroupBox;
|
||||
QGroupBox *cardLayoutGroupBox;
|
||||
QGroupBox *cardCountersGroupBox;
|
||||
QGroupBox *handGroupBox;
|
||||
QGroupBox *playmatGroupBox;
|
||||
QGroupBox *tableGroupBox;
|
||||
QGroupBox *cardCountersGroupBox;
|
||||
QList<QLabel *> cardCounterNames;
|
||||
QSpinBox minPlayersForMultiColumnLayoutEdit;
|
||||
QSpinBox maxFontSizeForCardsEdit;
|
||||
|
||||
public:
|
||||
AppearanceSettingsPage();
|
||||
|
|
|
|||
|
|
@ -425,28 +425,29 @@ void GeneralSettingsPage::updateStartupServerControlsVisibility()
|
|||
|
||||
void GeneralSettingsPage::retranslateUi()
|
||||
{
|
||||
const auto &settings = SettingsCache::instance();
|
||||
|
||||
languageGroupBox->setTitle(tr("Language settings"));
|
||||
languageLabel.setText(tr("Language:"));
|
||||
advertiseTranslationPageLabel.setText(
|
||||
QString("<a href='%1'>%2</a>").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
|
||||
|
||||
versionGroupBox->setTitle(tr("Version settings"));
|
||||
cardDatabaseGroupBox->setTitle(tr("Card database"));
|
||||
startupGroupBox->setTitle(tr("Startup settings"));
|
||||
|
||||
if (SettingsCache::instance().getIsPortableBuild()) {
|
||||
pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
|
||||
} else {
|
||||
pathsGroupBox->setTitle(tr("Paths"));
|
||||
}
|
||||
advertiseTranslationPageLabel.setText(
|
||||
QString("<a href='%1'>%2</a>").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
|
||||
deckPathLabel.setText(tr("Decks directory:"));
|
||||
filtersPathLabel.setText(tr("Filters directory:"));
|
||||
replaysPathLabel.setText(tr("Replays directory:"));
|
||||
picsPathLabel.setText(tr("Pictures directory:"));
|
||||
cardDatabasePathLabel.setText(tr("Card database:"));
|
||||
customCardDatabasePathLabel.setText(tr("Custom database directory:"));
|
||||
tokenDatabasePathLabel.setText(tr("Token database:"));
|
||||
updateReleaseChannelLabel.setText(tr("Update channel"));
|
||||
startupUpdateCheckCheckBox.setText(tr("Check for client updates on startup"));
|
||||
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
|
||||
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
|
||||
|
||||
// We can't change the strings after they're put into the QComboBox, so this is our workaround
|
||||
int oldIndex = updateReleaseChannelBox.currentIndex();
|
||||
updateReleaseChannelBox.clear();
|
||||
for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) {
|
||||
updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8()));
|
||||
}
|
||||
updateReleaseChannelBox.setCurrentIndex(oldIndex);
|
||||
|
||||
cardDatabaseGroupBox->setTitle(tr("Card database"));
|
||||
startupCardUpdateCheckBehaviorLabel.setText(tr("Check for card database updates on startup"));
|
||||
startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexNone, tr("Don't check"));
|
||||
startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexPrompt,
|
||||
|
|
@ -455,13 +456,8 @@ void GeneralSettingsPage::retranslateUi()
|
|||
tr("Always update in the background"));
|
||||
cardUpdateCheckIntervalLabel.setText(tr("Check for card database updates every"));
|
||||
cardUpdateCheckIntervalSpinBox.setSuffix(tr(" days"));
|
||||
|
||||
QDate lastCheckDate = settings.updates().getLastCardUpdateCheck();
|
||||
int daysAgo = lastCheckDate.daysTo(QDate::currentDate());
|
||||
lastCardUpdateCheckDateLabel.setText(
|
||||
tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo));
|
||||
|
||||
startupGroupBox->setTitle(tr("Startup settings"));
|
||||
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
|
||||
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
|
||||
showTipsOnStartup.setText(tr("Show tips on startup"));
|
||||
startupTabLabel.setText(tr("Startup tab:"));
|
||||
startupTabSelector.setItemText(StartupTab::StartupTabHome, tr("Home"));
|
||||
|
|
@ -477,18 +473,21 @@ void GeneralSettingsPage::retranslateUi()
|
|||
startupServerLabel.setText(tr("Server:"));
|
||||
startupRoomLabel.setText(tr("Room:"));
|
||||
startupRoomNameEdit->setPlaceholderText(tr("Room name"));
|
||||
|
||||
if (settings.getIsPortableBuild()) {
|
||||
pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
|
||||
} else {
|
||||
pathsGroupBox->setTitle(tr("Paths"));
|
||||
}
|
||||
deckPathLabel.setText(tr("Decks directory:"));
|
||||
filtersPathLabel.setText(tr("Filters directory:"));
|
||||
replaysPathLabel.setText(tr("Replays directory:"));
|
||||
picsPathLabel.setText(tr("Pictures directory:"));
|
||||
cardDatabasePathLabel.setText(tr("Card database:"));
|
||||
customCardDatabasePathLabel.setText(tr("Custom database directory:"));
|
||||
tokenDatabasePathLabel.setText(tr("Token database:"));
|
||||
resetAllPathsButton->setText(tr("Reset all paths"));
|
||||
}
|
||||
|
||||
const auto &settings = SettingsCache::instance();
|
||||
|
||||
QDate lastCheckDate = settings.updates().getLastCardUpdateCheck();
|
||||
int daysAgo = lastCheckDate.daysTo(QDate::currentDate());
|
||||
|
||||
lastCardUpdateCheckDateLabel.setText(
|
||||
tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo));
|
||||
|
||||
// We can't change the strings after they're put into the QComboBox, so this is our workaround
|
||||
int oldIndex = updateReleaseChannelBox.currentIndex();
|
||||
updateReleaseChannelBox.clear();
|
||||
for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) {
|
||||
updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8()));
|
||||
}
|
||||
updateReleaseChannelBox.setCurrentIndex(oldIndex);
|
||||
}
|
||||
|
|
@ -42,37 +42,6 @@ private:
|
|||
QGroupBox *startupGroupBox;
|
||||
QGroupBox *pathsGroupBox;
|
||||
|
||||
QLabel languageLabel;
|
||||
QComboBox languageBox;
|
||||
QLabel advertiseTranslationPageLabel;
|
||||
|
||||
QLabel updateReleaseChannelLabel;
|
||||
QComboBox updateReleaseChannelBox;
|
||||
QCheckBox startupUpdateCheckCheckBox;
|
||||
QCheckBox updateNotificationCheckBox;
|
||||
QCheckBox newVersionOracleCheckBox;
|
||||
|
||||
QLabel startupCardUpdateCheckBehaviorLabel;
|
||||
QComboBox startupCardUpdateCheckBehaviorSelector;
|
||||
QLabel cardUpdateCheckIntervalLabel;
|
||||
QSpinBox cardUpdateCheckIntervalSpinBox;
|
||||
QLabel lastCardUpdateCheckDateLabel;
|
||||
|
||||
QCheckBox showTipsOnStartup;
|
||||
QLabel startupTabLabel;
|
||||
QComboBox startupTabSelector;
|
||||
QLabel startupServerLabel;
|
||||
QComboBox startupServerSelector;
|
||||
QLabel startupRoomLabel;
|
||||
QLineEdit *startupRoomNameEdit;
|
||||
|
||||
QLabel deckPathLabel;
|
||||
QLabel filtersPathLabel;
|
||||
QLabel replaysPathLabel;
|
||||
QLabel picsPathLabel;
|
||||
QLabel cardDatabasePathLabel;
|
||||
QLabel customCardDatabasePathLabel;
|
||||
QLabel tokenDatabasePathLabel;
|
||||
QLineEdit *deckPathEdit;
|
||||
QLineEdit *filtersPathEdit;
|
||||
QLineEdit *replaysPathEdit;
|
||||
|
|
@ -82,6 +51,33 @@ private:
|
|||
QLineEdit *tokenDatabasePathEdit;
|
||||
QPushButton *resetAllPathsButton;
|
||||
QLabel *allPathsResetLabel;
|
||||
QComboBox languageBox;
|
||||
QCheckBox startupUpdateCheckCheckBox;
|
||||
QLabel startupCardUpdateCheckBehaviorLabel;
|
||||
QComboBox startupCardUpdateCheckBehaviorSelector;
|
||||
QLabel cardUpdateCheckIntervalLabel;
|
||||
QSpinBox cardUpdateCheckIntervalSpinBox;
|
||||
QLabel lastCardUpdateCheckDateLabel;
|
||||
QCheckBox updateNotificationCheckBox;
|
||||
QCheckBox newVersionOracleCheckBox;
|
||||
QComboBox updateReleaseChannelBox;
|
||||
QLabel languageLabel;
|
||||
QLabel deckPathLabel;
|
||||
QLabel filtersPathLabel;
|
||||
QLabel replaysPathLabel;
|
||||
QLabel picsPathLabel;
|
||||
QLabel cardDatabasePathLabel;
|
||||
QLabel customCardDatabasePathLabel;
|
||||
QLabel tokenDatabasePathLabel;
|
||||
QLabel updateReleaseChannelLabel;
|
||||
QLabel advertiseTranslationPageLabel;
|
||||
QCheckBox showTipsOnStartup;
|
||||
QLabel startupTabLabel;
|
||||
QComboBox startupTabSelector;
|
||||
QLabel startupServerLabel;
|
||||
QComboBox startupServerSelector;
|
||||
QLabel startupRoomLabel;
|
||||
QLineEdit *startupRoomNameEdit;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_GENERAL_SETTINGS_PAGE_H
|
||||
|
|
|
|||
|
|
@ -20,7 +20,26 @@ enum visualDeckStoragePromptForConversionIndex
|
|||
|
||||
UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
||||
{
|
||||
// general settings
|
||||
// general settings and notification settings
|
||||
notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setNotificationsEnabled);
|
||||
connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
|
||||
&UserInterfaceSettingsPage::setNotificationEnabled);
|
||||
|
||||
specNotificationsEnabledCheckBox.setChecked(
|
||||
SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled());
|
||||
specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setSpectatorNotificationsEnabled);
|
||||
|
||||
buddyConnectNotificationsEnabledCheckBox.setChecked(
|
||||
SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled());
|
||||
buddyConnectNotificationsEnabledCheckBox.setEnabled(
|
||||
SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED,
|
||||
&SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled);
|
||||
|
||||
doubleClickToPlayCheckBox.setChecked(SettingsCache::instance().userInterface().getDoubleClickToPlay());
|
||||
connect(&doubleClickToPlayCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setDoubleClickToPlay);
|
||||
|
|
@ -84,26 +103,6 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
|||
generalGroupBox = new QGroupBox;
|
||||
generalGroupBox->setLayout(generalGrid);
|
||||
|
||||
// notification settings
|
||||
notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setNotificationsEnabled);
|
||||
connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
|
||||
&UserInterfaceSettingsPage::setNotificationEnabled);
|
||||
|
||||
specNotificationsEnabledCheckBox.setChecked(
|
||||
SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled());
|
||||
specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(),
|
||||
&InterfaceSettings::setSpectatorNotificationsEnabled);
|
||||
|
||||
buddyConnectNotificationsEnabledCheckBox.setChecked(
|
||||
SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled());
|
||||
buddyConnectNotificationsEnabledCheckBox.setEnabled(
|
||||
SettingsCache::instance().userInterface().getNotificationsEnabled());
|
||||
connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED,
|
||||
&SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled);
|
||||
|
||||
auto *notificationsGrid = new QGridLayout;
|
||||
notificationsGrid->addWidget(¬ificationsEnabledCheckBox, 0, 0);
|
||||
notificationsGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0);
|
||||
|
|
@ -356,7 +355,6 @@ void UserInterfaceSettingsPage::retranslateUi()
|
|||
notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar"));
|
||||
specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating"));
|
||||
buddyConnectNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar when users in your buddy list connect"));
|
||||
|
||||
animationGroupBox->setTitle(tr("Animation settings"));
|
||||
enableAllAnimationsButton.setText(tr("&Enable all animations"));
|
||||
disableAllAnimationsButton.setText(tr("&Disable all animations"));
|
||||
|
|
@ -364,7 +362,6 @@ void UserInterfaceSettingsPage::retranslateUi()
|
|||
arrowDrawAnimationCheckBox.setText(tr("&Arrow draw 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"));
|
||||
|
|
@ -400,8 +397,8 @@ void UserInterfaceSettingsPage::retranslateUi()
|
|||
0, CommanderBracketNames::CommanderSpellbookBracketNames);
|
||||
commanderSpellbookIntegrationBracketNamingSelector.setItemText(
|
||||
1, CommanderBracketNames::OfficialCommanderBracketNames);
|
||||
commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer);
|
||||
|
||||
commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer);
|
||||
replayGroupBox->setTitle(tr("Replay settings"));
|
||||
rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:"));
|
||||
rewindBufferingMsBox.setSuffix(" ms");
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ private slots:
|
|||
void updateCommanderSpellbookUiState();
|
||||
|
||||
private:
|
||||
QCheckBox notificationsEnabledCheckBox;
|
||||
QCheckBox specNotificationsEnabledCheckBox;
|
||||
QCheckBox buddyConnectNotificationsEnabledCheckBox;
|
||||
QCheckBox doubleClickToPlayCheckBox;
|
||||
QCheckBox clickPlaysAllSelectedCheckBox;
|
||||
QCheckBox playToStackCheckBox;
|
||||
|
|
@ -34,18 +37,12 @@ private:
|
|||
QCheckBox showTotalSelectionCountCheckBox;
|
||||
QCheckBox useTearOffMenusCheckBox;
|
||||
QCheckBox keepGameChatFocusCheckBox;
|
||||
|
||||
QCheckBox notificationsEnabledCheckBox;
|
||||
QCheckBox specNotificationsEnabledCheckBox;
|
||||
QCheckBox buddyConnectNotificationsEnabledCheckBox;
|
||||
|
||||
QPushButton enableAllAnimationsButton;
|
||||
QPushButton disableAllAnimationsButton;
|
||||
QCheckBox tapAnimationCheckBox;
|
||||
QCheckBox arrowDrawAnimationCheckBox;
|
||||
QCheckBox lifeCounterAnimationsCheckBox;
|
||||
QCheckBox battlefieldFlashCheckBox;
|
||||
|
||||
QCheckBox openDeckInNewTabCheckBox;
|
||||
QLabel visualDeckStoragePromptForConversionLabel;
|
||||
QComboBox visualDeckStoragePromptForConversionSelector;
|
||||
|
|
@ -60,10 +57,8 @@ private:
|
|||
QLabel commanderSpellbookIntegrationUseOfficialBracketNamesLabel;
|
||||
QToolButton commanderSpellbookIntegrationUseOfficialBracketNamesExplainer;
|
||||
QComboBox commanderSpellbookIntegrationBracketNamingSelector;
|
||||
|
||||
QLabel rewindBufferingMsLabel;
|
||||
QSpinBox rewindBufferingMsBox;
|
||||
|
||||
QGroupBox *generalGroupBox;
|
||||
QGroupBox *notificationsGroupBox;
|
||||
QGroupBox *animationGroupBox;
|
||||
|
|
|
|||
|
|
@ -116,10 +116,9 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/)
|
|||
}
|
||||
|
||||
TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *parent)
|
||||
: QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabHome(nullptr),
|
||||
tabVisualDeckStorage(nullptr), tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr),
|
||||
tabReplays(nullptr), tabAdmin(nullptr), tabCardArtRules(nullptr), tabLog(nullptr), tabReport(nullptr),
|
||||
tabModeration(nullptr), isLocalGame(false)
|
||||
: QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabVisualDeckStorage(nullptr),
|
||||
tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr), tabReplays(nullptr), tabAdmin(nullptr),
|
||||
tabLog(nullptr), tabReport(nullptr), tabModeration(nullptr), isLocalGame(false)
|
||||
{
|
||||
setElideMode(Qt::ElideRight);
|
||||
setMovable(true);
|
||||
|
|
@ -246,7 +245,6 @@ void TabSupervisor::retranslateUi()
|
|||
aTabLog->setText(tr("Logs"));
|
||||
aTabReport->setText(tr("Report Queue"));
|
||||
aTabModeration->setText(tr("Moderation"));
|
||||
aTabCardArtRules->setText(tr("Card Art Rules"));
|
||||
|
||||
// tabs
|
||||
QList<Tab *> tabs;
|
||||
|
|
@ -258,7 +256,6 @@ void TabSupervisor::retranslateUi()
|
|||
tabs.append(tabLog);
|
||||
tabs.append(tabReport);
|
||||
tabs.append(tabModeration);
|
||||
tabs.append(tabCardArtRules);
|
||||
QMapIterator<int, TabRoom *> roomIterator(roomTabs);
|
||||
while (roomIterator.hasNext()) {
|
||||
tabs.append(roomIterator.next().value());
|
||||
|
|
@ -523,9 +520,7 @@ void TabSupervisor::start(const ServerInfo_User &_userInfo)
|
|||
if (SettingsCache::instance().tabs().getTabModerationOpen()) {
|
||||
openTabModeration();
|
||||
}
|
||||
if (SettingsCache::instance().tabs().getTabCardArtRulesOpen()) {
|
||||
openTabCardArtRules();
|
||||
}
|
||||
openTabCardArtRules();
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
|
|
@ -587,9 +582,6 @@ void TabSupervisor::stop()
|
|||
if (tabModeration) {
|
||||
tabModeration->close();
|
||||
}
|
||||
if (tabCardArtRules) {
|
||||
tabCardArtRules->close();
|
||||
}
|
||||
}
|
||||
|
||||
QList<Tab *> tabsToDelete;
|
||||
|
|
@ -783,7 +775,6 @@ void TabSupervisor::openTabAdmin()
|
|||
|
||||
void TabSupervisor::actTabCardArtRules(bool checked)
|
||||
{
|
||||
SettingsCache::instance().tabs().setTabCardArtRulesOpen(checked);
|
||||
if (checked && !tabCardArtRules) {
|
||||
openTabCardArtRules();
|
||||
setCurrentWidget(tabCardArtRules);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@ void VisualDeckStorageFolderDisplayWidget::continueDeckPass()
|
|||
}
|
||||
|
||||
const bool matches = index.data(VisualDeckStorageRoles::FilterMatchRole).toBool();
|
||||
deckPreviewWidget->setVisible(matches);
|
||||
if (matches == deckPreviewWidget->isHidden()) {
|
||||
deckPreviewWidget->setVisible(matches);
|
||||
}
|
||||
if (matches) {
|
||||
++visibleDeckCount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@
|
|||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/settings/network_settings.h>
|
||||
#include <libcockatrice/settings/personal_settings.h>
|
||||
#include <libcockatrice/utility/cryptoutil.h>
|
||||
|
||||
QTranslator *translator, *qtTranslator;
|
||||
RNG_Abstract *rng;
|
||||
|
|
@ -293,7 +292,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
rng = new RNG_SFMT(CryptoUtil::randomUInt64());
|
||||
rng = new RNG_SFMT;
|
||||
themeManager = new ThemeManager;
|
||||
soundEngine = new SoundEngine;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ public:
|
|||
[[nodiscard]] virtual bool getTabLogOpen() const = 0;
|
||||
[[nodiscard]] virtual bool getTabReportOpen() const = 0;
|
||||
[[nodiscard]] virtual bool getTabModerationOpen() const = 0;
|
||||
[[nodiscard]] virtual bool getTabCardArtRulesOpen() const = 0;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTERFACE_TABS_SETTINGS_PROVIDER_H
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ set(PROTO_FILES
|
|||
event_game_log_notice.proto
|
||||
event_game_say.proto
|
||||
event_game_state_changed.proto
|
||||
event_game_state_changed.proto
|
||||
event_join.proto
|
||||
event_join_room.proto
|
||||
event_kicked.proto
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "rng_sfmt.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <stdexcept>
|
||||
|
|
@ -10,11 +11,10 @@
|
|||
#define UINT64_MAX (~(uint64_t)0)
|
||||
#endif
|
||||
|
||||
RNG_SFMT::RNG_SFMT(uint64_t seed, QObject *parent) : RNG_Abstract(parent)
|
||||
RNG_SFMT::RNG_SFMT(QObject *parent) : RNG_Abstract(parent)
|
||||
{
|
||||
// initialize the random number generator with a 64bit seed, e.g. from a CSPRNG
|
||||
uint32_t seedArray[2] = {static_cast<uint32_t>(seed), static_cast<uint32_t>(seed >> 32)};
|
||||
sfmt_init_by_array(&sfmt, seedArray, 2);
|
||||
// initialize the random number generator with a 32bit integer seed (timestamp)
|
||||
sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ private:
|
|||
unsigned int cdf(unsigned int min, unsigned int max);
|
||||
|
||||
public:
|
||||
explicit RNG_SFMT(uint64_t seed, QObject *parent = nullptr);
|
||||
explicit RNG_SFMT(QObject *parent = nullptr);
|
||||
unsigned int rand(int min, int max) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -106,11 +106,6 @@ bool TabsSettings::getTabModerationOpen() const
|
|||
return getValue("moderation", QString(), QString(), false).toBool();
|
||||
}
|
||||
|
||||
bool TabsSettings::getTabCardArtRulesOpen() const
|
||||
{
|
||||
return getValue("cardArtRules", QString(), QString(), false).toBool();
|
||||
}
|
||||
|
||||
void TabsSettings::setTabVisualDeckStorageOpen(bool value)
|
||||
{
|
||||
setValue(value, "visualDeckStorage");
|
||||
|
|
@ -155,8 +150,3 @@ void TabsSettings::setTabModerationOpen(bool value)
|
|||
{
|
||||
setValue(value, "moderation");
|
||||
}
|
||||
|
||||
void TabsSettings::setTabCardArtRulesOpen(bool value)
|
||||
{
|
||||
setValue(value, "cardArtRules");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ public:
|
|||
[[nodiscard]] bool getTabLogOpen() const override;
|
||||
[[nodiscard]] bool getTabReportOpen() const override;
|
||||
[[nodiscard]] bool getTabModerationOpen() const override;
|
||||
[[nodiscard]] bool getTabCardArtRulesOpen() const override;
|
||||
|
||||
void setStartupTabIndex(int value);
|
||||
void setStartupServerHost(const QString &host);
|
||||
|
|
@ -58,7 +57,6 @@ public:
|
|||
void setTabLogOpen(bool value);
|
||||
void setTabReportOpen(bool value);
|
||||
void setTabModerationOpen(bool value);
|
||||
void setTabCardArtRulesOpen(bool value);
|
||||
|
||||
signals:
|
||||
void startupTabIndexChanged(int index);
|
||||
|
|
|
|||
|
|
@ -6,15 +6,13 @@ set(CMAKE_AUTOUIC ON)
|
|||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(UTILITY_SOURCES
|
||||
libcockatrice/utility/cryptoutil.cpp libcockatrice/utility/expression.cpp libcockatrice/utility/levenshtein.cpp
|
||||
libcockatrice/utility/passwordhasher.cpp libcockatrice/utility/server_rate_limiter.cpp
|
||||
libcockatrice/utility/warning_categories.cpp
|
||||
libcockatrice/utility/expression.cpp libcockatrice/utility/levenshtein.cpp libcockatrice/utility/passwordhasher.cpp
|
||||
libcockatrice/utility/server_rate_limiter.cpp libcockatrice/utility/warning_categories.cpp
|
||||
)
|
||||
|
||||
set(UTILITY_HEADERS
|
||||
libcockatrice/utility/card_ref.h
|
||||
libcockatrice/utility/color.h
|
||||
libcockatrice/utility/cryptoutil.h
|
||||
libcockatrice/utility/expression.h
|
||||
libcockatrice/utility/levenshtein.h
|
||||
libcockatrice/utility/macros.h
|
||||
|
|
@ -34,9 +32,7 @@ add_library(libcockatrice_utility STATIC ${UTILITY_SOURCES} ${UTILITY_HEADERS})
|
|||
|
||||
target_include_directories(libcockatrice_utility PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
target_link_libraries(libcockatrice_utility PUBLIC libcockatrice_rng OpenSSL::Crypto ${QT_CORE_MODULE})
|
||||
target_link_libraries(libcockatrice_utility PUBLIC libcockatrice_rng ${QT_CORE_MODULE})
|
||||
|
||||
set(ORACLE_LIBS)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#include "cryptoutil.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
namespace CryptoUtil
|
||||
{
|
||||
QByteArray randomBytes(int count)
|
||||
{
|
||||
QByteArray bytes(count, '\0');
|
||||
if (RAND_bytes(reinterpret_cast<unsigned char *>(bytes.data()), count) != 1) {
|
||||
// Randomness failure is fatal: never fall back to a predictable source.
|
||||
qFatal("CryptoUtil::randomBytes: RAND_bytes failed");
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
quint64 randomUInt64()
|
||||
{
|
||||
quint64 value;
|
||||
if (RAND_bytes(reinterpret_cast<unsigned char *>(&value), sizeof(value)) != 1) {
|
||||
qFatal("CryptoUtil::randomUInt64: RAND_bytes failed");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
} // namespace CryptoUtil
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef CRYPTOUTIL_H
|
||||
#define CRYPTOUTIL_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace CryptoUtil
|
||||
{
|
||||
QByteArray randomBytes(int count);
|
||||
quint64 randomUInt64();
|
||||
} // namespace CryptoUtil
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "passwordhasher.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <libcockatrice/utility/cryptoutil.h>
|
||||
#include <libcockatrice/rng/rng_sfmt.h>
|
||||
|
||||
QString PasswordHasher::computeHash(const QString &password, const QString &salt)
|
||||
{
|
||||
|
|
@ -21,28 +21,12 @@ QString PasswordHasher::generateRandomSalt(const int len)
|
|||
static const char alphanum[] = "0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const int size = sizeof(alphanum) - 1;
|
||||
|
||||
// Two bytes per character, corrected for modulo bias via rejection sampling.
|
||||
const int bucketSize = 65536 / size;
|
||||
const int limit = bucketSize * size;
|
||||
|
||||
QString ret;
|
||||
ret.reserve(len);
|
||||
QByteArray random = CryptoUtil::randomBytes(len * 2);
|
||||
int bytesUsed = 0;
|
||||
int size = sizeof(alphanum) - 1;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
unsigned int value;
|
||||
do {
|
||||
if (bytesUsed >= random.size()) {
|
||||
random = CryptoUtil::randomBytes(len * 2);
|
||||
bytesUsed = 0;
|
||||
}
|
||||
value = static_cast<unsigned int>(static_cast<unsigned char>(random.at(bytesUsed))) << 8 |
|
||||
static_cast<unsigned int>(static_cast<unsigned char>(random.at(bytesUsed + 1)));
|
||||
bytesUsed += 2;
|
||||
} while (value >= limit);
|
||||
ret.append(alphanum[value / bucketSize]);
|
||||
ret.append(alphanum[rng->rand(0, size)]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -50,5 +34,5 @@ QString PasswordHasher::generateRandomSalt(const int len)
|
|||
|
||||
QString PasswordHasher::generateActivationToken()
|
||||
{
|
||||
return QString(CryptoUtil::randomBytes(16).toBase64().left(16));
|
||||
return QCryptographicHash::hash(generateRandomSalt().toUtf8(), QCryptographicHash::Md5).toBase64().left(16);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
#include <QtGlobal>
|
||||
#include <iostream>
|
||||
#include <libcockatrice/rng/rng_sfmt.h>
|
||||
#include <libcockatrice/utility/cryptoutil.h>
|
||||
#include <libcockatrice/utility/passwordhasher.h>
|
||||
|
||||
RNG_Abstract *rng;
|
||||
|
|
@ -170,7 +169,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
signalhandler = new SignalHandler();
|
||||
|
||||
rng = new RNG_SFMT(CryptoUtil::randomUInt64());
|
||||
rng = new RNG_SFMT;
|
||||
|
||||
std::cerr << "Servatrice " << VERSION_STRING << " starting." << std::endl;
|
||||
std::cerr << "-------------------------" << std::endl;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,25 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include <cstring>
|
||||
#include <libcockatrice/rng/rng_abstract.h>
|
||||
#include <libcockatrice/rng/rng_sfmt.h>
|
||||
#include <libcockatrice/utility/passwordhasher.h>
|
||||
|
||||
RNG_Abstract *rng;
|
||||
|
||||
namespace
|
||||
{
|
||||
class PasswordHashTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
rng = new RNG_SFMT;
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
delete rng;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(PasswordHashTest, RegressionTest)
|
||||
{
|
||||
|
|
@ -13,29 +29,6 @@ TEST(PasswordHashTest, RegressionTest)
|
|||
QString hash = PasswordHasher::computeHash(password, salt);
|
||||
ASSERT_EQ(hash, salt + expected) << "The computed hash value remains the same";
|
||||
}
|
||||
|
||||
TEST(PasswordHashTest, SaltUsesAlphanumericCharset)
|
||||
{
|
||||
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
const QString salt = PasswordHasher::generateRandomSalt();
|
||||
ASSERT_EQ(salt.size(), 16);
|
||||
for (const QChar &c : salt) {
|
||||
ASSERT_NE(strchr(alphanum, c.toLatin1()), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PasswordHashTest, SaltsAreUnique)
|
||||
{
|
||||
const QString salt1 = PasswordHasher::generateRandomSalt();
|
||||
const QString salt2 = PasswordHasher::generateRandomSalt();
|
||||
ASSERT_NE(salt1, salt2);
|
||||
}
|
||||
|
||||
TEST(PasswordHashTest, TokenHasExpectedLength)
|
||||
{
|
||||
const QString token = PasswordHasher::generateActivationToken();
|
||||
ASSERT_EQ(token.size(), 16);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
|
|
|||
|
|
@ -238,12 +238,6 @@ TEST_F(SettingsDefaultsTest, Tabs_ModerationOpen_Default)
|
|||
ASSERT_EQ(s.getTabModerationOpen(), false);
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Tabs_CardArtRulesOpen_Default)
|
||||
{
|
||||
TabsSettings s(settingsPath, nullptr);
|
||||
ASSERT_EQ(s.getTabCardArtRulesOpen(), false);
|
||||
}
|
||||
|
||||
// --- ChatSettings ---
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Chat_Mention_Default)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue