mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-10 12:23:58 -07:00
Merge branch 'master' into 6269/ci/strip-fat-bins
This commit is contained in:
commit
dcafc7c28e
49 changed files with 906 additions and 253 deletions
|
|
@ -156,6 +156,7 @@ function ccachestatsverbose() {
|
|||
|
||||
# Compile
|
||||
if [[ $RUNNER_OS == macOS ]]; then
|
||||
|
||||
if [[ $TARGET_MACOS_VERSION ]]; then
|
||||
# CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla cmake flag needed to compile to target macOS version
|
||||
flags+=("-DCMAKE_OSX_DEPLOYMENT_TARGET=$TARGET_MACOS_VERSION")
|
||||
|
|
@ -202,17 +203,18 @@ if [[ $RUNNER_OS == macOS ]]; then
|
|||
hdiutil_script="/tmp/hdiutil.sh"
|
||||
# shellcheck disable=SC2016
|
||||
echo '#!/bin/bash
|
||||
i=0
|
||||
while ! hdiutil "$@"; do
|
||||
i=0
|
||||
while ! hdiutil "$@"; do
|
||||
if (( ++i >= 10 )); then
|
||||
echo "Error: hdiutil failed $i times!" >&2
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done' >"$hdiutil_script"
|
||||
done' >"$hdiutil_script"
|
||||
chmod +x "$hdiutil_script"
|
||||
flags+=(-DCPACK_COMMAND_HDIUTIL="$hdiutil_script")
|
||||
fi
|
||||
|
||||
elif [[ $RUNNER_OS == Windows ]]; then
|
||||
# Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
|
||||
# and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt
|
||||
|
|
@ -242,6 +244,19 @@ if [[ $USE_CCACHE ]]; then
|
|||
echo "::endgroup::"
|
||||
fi
|
||||
|
||||
if [[ $RUNNER_OS == macOS ]]; then
|
||||
echo "::group::Inspect Mach-O binaries"
|
||||
for app in cockatrice oracle servatrice dbconverter; do
|
||||
binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app"
|
||||
echo "Inspecting $app..."
|
||||
vtool -show-build "$binary"
|
||||
file "$binary"
|
||||
lipo -info "$binary"
|
||||
echo ""
|
||||
done
|
||||
echo "::endgroup::"
|
||||
fi
|
||||
|
||||
if [[ $MAKE_TEST ]]; then
|
||||
echo "::group::Run tests"
|
||||
ctest -C "$BUILDTYPE" --output-on-failure
|
||||
|
|
@ -256,7 +271,6 @@ fi
|
|||
|
||||
if [[ $MAKE_PACKAGE ]]; then
|
||||
echo "::group::Create package"
|
||||
|
||||
cmake --build . --target package --config "$BUILDTYPE"
|
||||
echo "::endgroup::"
|
||||
|
||||
|
|
|
|||
3
.github/workflows/documentation-build.yml
vendored
3
.github/workflows/documentation-build.yml
vendored
|
|
@ -11,6 +11,9 @@ on:
|
|||
- 'doxygen_style.css'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
COCKATRICE_REF: ${{ github.ref_name }} # Tag name if the commit is tagged, otherwise branch name
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
name: Doxygen
|
||||
|
|
|
|||
11
Doxyfile
11
Doxyfile
|
|
@ -1,4 +1,5 @@
|
|||
# Doxyfile 1.14.0
|
||||
# Doxygen Docs: https://www.doxygen.nl/manual
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# Doxygen (www.doxygen.org) for a project.
|
||||
|
|
@ -48,13 +49,13 @@ PROJECT_NAME = "Cockatrice"
|
|||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2.11
|
||||
PROJECT_NUMBER = $(COCKATRICE_REF)
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewers a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_BRIEF = A cross-platform virtual tabletop for multiplayer card games
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||
# in the documentation. The maximum height of the logo should not exceed 55
|
||||
|
|
@ -839,7 +840,7 @@ FILE_VERSION_FILTER =
|
|||
# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE
|
||||
# tag is left empty.
|
||||
|
||||
LAYOUT_FILE = DoxygenLayout.xml
|
||||
LAYOUT_FILE = doc/doxygen/DoxygenLayout.xml
|
||||
|
||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
||||
# the reference definitions. This must be a list of .bib files. The .bib
|
||||
|
|
@ -1438,7 +1439,7 @@ HTML_EXTRA_FILES = doc/doxygen/js/graph_toggle.js
|
|||
# The default value is: AUTO_LIGHT.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_COLORSTYLE = DARK
|
||||
HTML_COLORSTYLE = AUTO_DARK
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
|
|
@ -2021,7 +2022,7 @@ EXTRA_SEARCH_MAPPINGS =
|
|||
# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output.
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_LATEX = YES
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ set(cockatrice_SOURCES
|
|||
src/interface/widgets/replay/replay_timeline_widget.cpp
|
||||
src/interface/widgets/server/chat_view/chat_view.cpp
|
||||
src/interface/widgets/server/game_selector.cpp
|
||||
src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
|
||||
src/interface/widgets/server/games_model.cpp
|
||||
src/interface/widgets/server/handle_public_servers.cpp
|
||||
src/interface/widgets/server/remote/remote_decklist_tree_widget.cpp
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public:
|
|||
}
|
||||
|
||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
||||
loader->resolveSetNameAndNumberToProviderID();
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
|
@ -95,7 +95,7 @@ public:
|
|||
}
|
||||
|
||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
||||
loader->resolveSetNameAndNumberToProviderID();
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
|
||||
|
||||
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||
if (!commandersObj.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ void AbstractCardItem::refreshCardInfo()
|
|||
exactCard = CardDatabaseManager::query()->getCard(cardRef);
|
||||
|
||||
if (!exactCard && !cardRef.name.isEmpty()) {
|
||||
auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, false, false, -1, false);
|
||||
CardInfo::UiAttributes attributes = {.tableRow = -1};
|
||||
auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, attributes);
|
||||
exactCard = ExactCard(info);
|
||||
}
|
||||
if (exactCard) {
|
||||
|
|
|
|||
|
|
@ -238,8 +238,8 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
if (startZone->getName().compare("hand") == 0) {
|
||||
startCard->playCard(false);
|
||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||
if (ci && ((!SettingsCache::instance().getPlayToStack() && ci->getTableRow() == 3) ||
|
||||
(SettingsCache::instance().getPlayToStack() && ci->getTableRow() != 0 &&
|
||||
if (ci && ((!SettingsCache::instance().getPlayToStack() && ci->getUiAttributes().tableRow == 3) ||
|
||||
(SettingsCache::instance().getPlayToStack() && ci->getUiAttributes().tableRow != 0 &&
|
||||
startCard->getZone()->getName().toStdString() != "stack")))
|
||||
cmd.set_start_zone("stack");
|
||||
else
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
|
|||
|
||||
const CardInfo &info = exactCard.getInfo();
|
||||
|
||||
int tableRow = info.getTableRow();
|
||||
int tableRow = info.getUiAttributes().tableRow;
|
||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||
QString currentZone = card->getZone()->getName();
|
||||
if (currentZone == "stack" && tableRow == 3) {
|
||||
|
|
@ -72,13 +72,13 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
|
|||
cmd.set_x(-1);
|
||||
cmd.set_y(0);
|
||||
} else {
|
||||
tableRow = faceDown ? 2 : info.getTableRow();
|
||||
tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow));
|
||||
cardToMove->set_face_down(faceDown);
|
||||
if (!faceDown) {
|
||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||
}
|
||||
cardToMove->set_tapped(!faceDown && info.getCipt());
|
||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||
if (tableRow != 3)
|
||||
cmd.set_target_zone("table");
|
||||
cmd.set_x(gridPoint.x());
|
||||
|
|
@ -111,7 +111,7 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
|||
|
||||
const CardInfo &info = exactCard.getInfo();
|
||||
|
||||
int tableRow = faceDown ? 2 : info.getTableRow();
|
||||
int tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||
// default instant/sorcery cards to the noncreatures row
|
||||
if (tableRow > 2) {
|
||||
tableRow = 1;
|
||||
|
|
@ -122,7 +122,7 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
|||
if (!faceDown) {
|
||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||
}
|
||||
cardToMove->set_tapped(!faceDown && info.getCipt());
|
||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||
cmd.set_target_zone("table");
|
||||
cmd.set_x(gridPoint.x());
|
||||
cmd.set_y(gridPoint.y());
|
||||
|
|
@ -859,7 +859,7 @@ void PlayerActions::actCreateToken()
|
|||
ExactCard correctedCard = CardDatabaseManager::query()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
|
||||
if (correctedCard) {
|
||||
lastTokenInfo.name = correctedCard.getName();
|
||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow());
|
||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getUiAttributes().tableRow);
|
||||
if (lastTokenInfo.pt.isEmpty()) {
|
||||
lastTokenInfo.pt = correctedCard.getInfo().getPowTough();
|
||||
}
|
||||
|
|
@ -910,7 +910,7 @@ void PlayerActions::setLastToken(CardInfoPtr cardInfo)
|
|||
.providerId =
|
||||
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
|
||||
|
||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow());
|
||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow);
|
||||
|
||||
utilityMenu->setAndEnableCreateAnotherTokenAction(tr("C&reate another %1 token").arg(lastTokenInfo.name));
|
||||
}
|
||||
|
|
@ -1080,7 +1080,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
|||
|
||||
// get the target token's location
|
||||
// TODO: Define this QPoint into its own function along with the one below
|
||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getTableRow()));
|
||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow));
|
||||
|
||||
// create the token for the related card
|
||||
Command_CreateToken cmd;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ void TableZoneLogic::addCardImpl(CardItem *card, int _x, int _y)
|
|||
if (!card->getFaceDown() && card->getPT().isEmpty()) {
|
||||
card->setPT(card->getCardInfo().getPowTough());
|
||||
}
|
||||
if (card->getCardInfo().getCipt() && card->getCardInfo().getLandscapeOrientation()) {
|
||||
if (card->getCardInfo().getUiAttributes().cipt && card->getCardInfo().getUiAttributes().landscapeOrientation) {
|
||||
card->setDoesntUntap(true);
|
||||
}
|
||||
card->setGridPoint(QPoint(_x, _y));
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image)
|
|||
qCDebug(CardPictureLoaderLog) << "Caching NULL pixmap for" << card.getName();
|
||||
QPixmapCache::insert(card.getPixmapCacheKey(), QPixmap());
|
||||
} else {
|
||||
if (card.getInfo().getUpsideDownArt()) {
|
||||
if (card.getInfo().getUiAttributes().upsideDownArt) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 9, 0))
|
||||
QImage mirrorImage = image.flipped(Qt::Horizontal | Qt::Vertical);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -276,9 +276,11 @@ static QString toDecklistExportString(const DecklistCardNode *card)
|
|||
|
||||
/**
|
||||
* Export deck to decklist function, called to format the deck in a way to be sent to a server
|
||||
*
|
||||
* @param deckList The decklist to export
|
||||
* @param website The website we're sending the deck to
|
||||
*/
|
||||
QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
|
||||
QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website)
|
||||
{
|
||||
// Add the base url
|
||||
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
|
||||
|
|
@ -345,8 +347,10 @@ struct SetProviderIdToPreferred
|
|||
/**
|
||||
* This function iterates through each card in the decklist and sets the providerId
|
||||
* on each card based on its set name and collector number.
|
||||
*
|
||||
* @param deckList The decklist to modify
|
||||
*/
|
||||
void DeckLoader::setProviderIdToPreferredPrinting()
|
||||
void DeckLoader::setProviderIdToPreferredPrinting(const DeckList *deckList)
|
||||
{
|
||||
// Set up the struct to call.
|
||||
SetProviderIdToPreferred setProviderIdToPreferred;
|
||||
|
|
@ -357,8 +361,10 @@ void DeckLoader::setProviderIdToPreferredPrinting()
|
|||
|
||||
/**
|
||||
* Sets the providerId on each card in the decklist based on its set name and collector number.
|
||||
*
|
||||
* @param deckList The decklist to modify
|
||||
*/
|
||||
void DeckLoader::resolveSetNameAndNumberToProviderID()
|
||||
void DeckLoader::resolveSetNameAndNumberToProviderID(const DeckList *deckList)
|
||||
{
|
||||
auto setProviderId = [](const auto node, const auto card) {
|
||||
Q_UNUSED(node);
|
||||
|
|
@ -397,8 +403,10 @@ struct ClearSetNameNumberAndProviderId
|
|||
|
||||
/**
|
||||
* Clears the set name and numbers on each card in the decklist.
|
||||
*
|
||||
* @param deckList The decklist to modify
|
||||
*/
|
||||
void DeckLoader::clearSetNamesAndNumbers()
|
||||
void DeckLoader::clearSetNamesAndNumbers(const DeckList *deckList)
|
||||
{
|
||||
auto clearSetNameAndNumber = [](const auto node, auto card) {
|
||||
Q_UNUSED(node)
|
||||
|
|
@ -419,19 +427,22 @@ DeckLoader::FileFormat DeckLoader::getFormatFromName(const QString &fileName)
|
|||
return PlainTextFormat;
|
||||
}
|
||||
|
||||
void DeckLoader::saveToClipboard(bool addComments, bool addSetNameAndNumber) const
|
||||
void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, bool addSetNameAndNumber)
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
saveToStream_Plain(stream, addComments, addSetNameAndNumber);
|
||||
saveToStream_Plain(stream, deckList, addComments, addSetNameAndNumber);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Selection);
|
||||
}
|
||||
|
||||
bool DeckLoader::saveToStream_Plain(QTextStream &out, bool addComments, bool addSetNameAndNumber) const
|
||||
bool DeckLoader::saveToStream_Plain(QTextStream &out,
|
||||
const DeckList *deckList,
|
||||
bool addComments,
|
||||
bool addSetNameAndNumber)
|
||||
{
|
||||
if (addComments) {
|
||||
saveToStream_DeckHeader(out);
|
||||
saveToStream_DeckHeader(out, deckList);
|
||||
}
|
||||
|
||||
// loop zones
|
||||
|
|
@ -447,7 +458,7 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out, bool addComments, bool add
|
|||
return true;
|
||||
}
|
||||
|
||||
void DeckLoader::saveToStream_DeckHeader(QTextStream &out) const
|
||||
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList)
|
||||
{
|
||||
if (!deckList->getName().isEmpty()) {
|
||||
out << "// " << deckList->getName() << "\n\n";
|
||||
|
|
@ -465,7 +476,7 @@ void DeckLoader::saveToStream_DeckHeader(QTextStream &out) const
|
|||
void DeckLoader::saveToStream_DeckZone(QTextStream &out,
|
||||
const InnerDecklistNode *zoneNode,
|
||||
bool addComments,
|
||||
bool addSetNameAndNumber) const
|
||||
bool addSetNameAndNumber)
|
||||
{
|
||||
// group cards by card type and count the subtotals
|
||||
QMultiMap<QString, DecklistCardNode *> cardsByType;
|
||||
|
|
@ -513,7 +524,7 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
|
|||
const InnerDecklistNode *zoneNode,
|
||||
QList<DecklistCardNode *> cards,
|
||||
bool addComments,
|
||||
bool addSetNameAndNumber) const
|
||||
bool addSetNameAndNumber)
|
||||
{
|
||||
// QMultiMap sorts values in reverse order
|
||||
for (int i = cards.size() - 1; i >= 0; --i) {
|
||||
|
|
@ -589,7 +600,7 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
|
|||
return result;
|
||||
}
|
||||
|
||||
QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneName)
|
||||
QString DeckLoader::getCardZoneFromName(const QString &cardName, QString currentZoneName)
|
||||
{
|
||||
CardInfoPtr card = CardDatabaseManager::query()->getCardInfo(cardName);
|
||||
|
||||
|
|
@ -600,7 +611,7 @@ QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneNam
|
|||
return currentZoneName;
|
||||
}
|
||||
|
||||
QString DeckLoader::getCompleteCardName(const QString &cardName) const
|
||||
QString DeckLoader::getCompleteCardName(const QString &cardName)
|
||||
{
|
||||
if (CardDatabaseManager::getInstance()) {
|
||||
ExactCard temp = CardDatabaseManager::query()->guessCard({cardName});
|
||||
|
|
@ -672,7 +683,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node)
|
|||
cursor->movePosition(QTextCursor::End);
|
||||
}
|
||||
|
||||
void DeckLoader::printDeckList(QPrinter *printer)
|
||||
void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
|
||||
{
|
||||
QTextDocument doc;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@ signals:
|
|||
void deckLoaded();
|
||||
void loadFinished(bool success);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Prints the decklist to the provided QPrinter.
|
||||
* @param printer The printer to render the decklist to.
|
||||
*/
|
||||
void printDeckList(QPrinter *printer);
|
||||
|
||||
public:
|
||||
enum FileFormat
|
||||
{
|
||||
|
|
@ -84,7 +77,7 @@ public:
|
|||
return getLastFileName().isEmpty() && getLastRemoteDeckId() == -1;
|
||||
}
|
||||
|
||||
void clearSetNamesAndNumbers();
|
||||
static void clearSetNamesAndNumbers(const DeckList *deckList);
|
||||
static FileFormat getFormatFromName(const QString &fileName);
|
||||
|
||||
bool loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest = false);
|
||||
|
|
@ -92,15 +85,25 @@ public:
|
|||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
||||
bool saveToFile(const QString &fileName, FileFormat fmt);
|
||||
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
|
||||
QString exportDeckToDecklist(DecklistWebsite website);
|
||||
void setProviderIdToPreferredPrinting();
|
||||
|
||||
void resolveSetNameAndNumberToProviderID();
|
||||
static QString exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website);
|
||||
|
||||
void saveToClipboard(bool addComments = true, bool addSetNameAndNumber = true) const;
|
||||
static void setProviderIdToPreferredPrinting(const DeckList *deckList);
|
||||
static void resolveSetNameAndNumberToProviderID(const DeckList *deckList);
|
||||
|
||||
static void saveToClipboard(const DeckList *deckList, bool addComments = true, bool addSetNameAndNumber = true);
|
||||
static bool saveToStream_Plain(QTextStream &out,
|
||||
const DeckList *deckList,
|
||||
bool addComments = true,
|
||||
bool addSetNameAndNumber = true);
|
||||
|
||||
/**
|
||||
* @brief Prints the decklist to the provided QPrinter.
|
||||
* @param printer The printer to render the decklist to.
|
||||
* @param deckList
|
||||
*/
|
||||
static void printDeckList(QPrinter *printer, const DeckList *deckList);
|
||||
|
||||
// overload
|
||||
bool saveToStream_Plain(QTextStream &out, bool addComments = true, bool addSetNameAndNumber = true) const;
|
||||
bool convertToCockatriceFormat(QString fileName);
|
||||
|
||||
DeckList *getDeckList()
|
||||
|
|
@ -109,21 +112,21 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node);
|
||||
static void printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node);
|
||||
static void saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList);
|
||||
|
||||
protected:
|
||||
void saveToStream_DeckHeader(QTextStream &out) const;
|
||||
void saveToStream_DeckZone(QTextStream &out,
|
||||
static void saveToStream_DeckZone(QTextStream &out,
|
||||
const InnerDecklistNode *zoneNode,
|
||||
bool addComments = true,
|
||||
bool addSetNameAndNumber = true) const;
|
||||
void saveToStream_DeckZoneCards(QTextStream &out,
|
||||
bool addSetNameAndNumber = true);
|
||||
static void saveToStream_DeckZoneCards(QTextStream &out,
|
||||
const InnerDecklistNode *zoneNode,
|
||||
QList<DecklistCardNode *> cards,
|
||||
bool addComments = true,
|
||||
bool addSetNameAndNumber = true) const;
|
||||
[[nodiscard]] QString getCardZoneFromName(QString cardName, QString currentZoneName);
|
||||
[[nodiscard]] QString getCompleteCardName(const QString &cardName) const;
|
||||
bool addSetNameAndNumber = true);
|
||||
|
||||
[[nodiscard]] static QString getCardZoneFromName(const QString &cardName, QString currentZoneName);
|
||||
[[nodiscard]] static QString getCompleteCardName(const QString &cardName);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
|
|||
|
||||
QPixmap transformedPixmap = resizedPixmap; // Default pixmap
|
||||
if (SettingsCache::instance().getAutoRotateSidewaysLayoutCards()) {
|
||||
if (exactCard.getInfo().getLandscapeOrientation()) {
|
||||
if (exactCard.getInfo().getUiAttributes().landscapeOrientation) {
|
||||
// Rotate pixmap 90 degrees to the left
|
||||
QTransform transform;
|
||||
transform.rotate(90);
|
||||
|
|
|
|||
|
|
@ -102,15 +102,20 @@ void DlgCreateGame::sharedCtor()
|
|||
startingLifeTotalEdit->setValue(20);
|
||||
startingLifeTotalLabel->setBuddy(startingLifeTotalEdit);
|
||||
|
||||
shareDecklistsOnLoadLabel = new QLabel(tr("Open decklists in lobby"));
|
||||
shareDecklistsOnLoadCheckBox = new QCheckBox();
|
||||
shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox);
|
||||
shareDecklistsOnLoadCheckBox = new QCheckBox(tr("Open decklists in lobby"));
|
||||
|
||||
createGameAsJudgeCheckBox = new QCheckBox(tr("Create game as judge"));
|
||||
|
||||
auto *gameSetupOptionsLayout = new QGridLayout;
|
||||
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
|
||||
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
|
||||
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0);
|
||||
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 1);
|
||||
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 0);
|
||||
if (room->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
||||
gameSetupOptionsLayout->addWidget(createGameAsJudgeCheckBox, 2, 0);
|
||||
} else {
|
||||
createGameAsJudgeCheckBox->setChecked(false);
|
||||
createGameAsJudgeCheckBox->setHidden(true);
|
||||
}
|
||||
gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options"));
|
||||
gameSetupOptionsGroupBox->setLayout(gameSetupOptionsLayout);
|
||||
|
||||
|
|
@ -245,6 +250,7 @@ void DlgCreateGame::actReset()
|
|||
|
||||
startingLifeTotalEdit->setValue(20);
|
||||
shareDecklistsOnLoadCheckBox->setChecked(false);
|
||||
createGameAsJudgeCheckBox->setChecked(false);
|
||||
|
||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||
while (gameTypeCheckBoxIterator.hasNext()) {
|
||||
|
|
@ -270,7 +276,7 @@ void DlgCreateGame::actOK()
|
|||
cmd.set_spectators_need_password(spectatorsNeedPasswordCheckBox->isChecked());
|
||||
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
|
||||
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
|
||||
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
|
||||
cmd.set_join_as_judge(createGameAsJudgeCheckBox->isChecked());
|
||||
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
|
||||
cmd.set_starting_life_total(startingLifeTotalEdit->value());
|
||||
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ private:
|
|||
QSpinBox *maxPlayersEdit, *startingLifeTotalEdit;
|
||||
QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox;
|
||||
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
|
||||
*spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox;
|
||||
*spectatorsSeeEverythingCheckBox, *createGameAsJudgeCheckBox, *createGameAsSpectatorCheckBox;
|
||||
QCheckBox *shareDecklistsOnLoadCheckBox;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QPushButton *clearButton;
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ void DlgEditTokens::actAddToken()
|
|||
QString setName = CardSet::TOKENS_SETNAME;
|
||||
SetToPrintingsMap sets;
|
||||
sets[setName].append(PrintingInfo(databaseModel->getDatabase()->getSet(setName)));
|
||||
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(),
|
||||
QList<CardRelation *>(), sets, false, false, -1, false);
|
||||
CardInfo::UiAttributes attributes = {.tableRow = -1};
|
||||
CardInfoPtr card = CardInfo::newInstance(name, "", true, {}, {}, {}, sets, attributes);
|
||||
card->setCardType("Token");
|
||||
|
||||
databaseModel->getDatabase()->addCard(card);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
|||
hideIgnoredUserGames = new QCheckBox(tr("Hide 'ignored user' games"));
|
||||
hideIgnoredUserGames->setChecked(gamesProxyModel->getHideIgnoredUserGames());
|
||||
|
||||
hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddy"));
|
||||
hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddies"));
|
||||
hideNotBuddyCreatedGames->setChecked(gamesProxyModel->getHideNotBuddyCreatedGames());
|
||||
|
||||
hideOpenDecklistGames = new QCheckBox(tr("Hide games with forced open decklists"));
|
||||
|
|
@ -56,7 +56,7 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
|||
auto *gameNameFilterLabel = new QLabel(tr("Game &description:"));
|
||||
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
|
||||
creatorNameFilterEdit = new QLineEdit;
|
||||
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilter());
|
||||
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilters().join(", "));
|
||||
auto *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
|
||||
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
|
||||
|
||||
|
|
@ -232,9 +232,9 @@ QString DlgFilterGames::getGameNameFilter() const
|
|||
return gameNameFilterEdit->text();
|
||||
}
|
||||
|
||||
QString DlgFilterGames::getCreatorNameFilter() const
|
||||
QStringList DlgFilterGames::getCreatorNameFilters() const
|
||||
{
|
||||
return creatorNameFilterEdit->text();
|
||||
return creatorNameFilterEdit->text().split(",", Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
QSet<int> DlgFilterGames::getGameTypeFilter() const
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public:
|
|||
bool getHideNotBuddyCreatedGames() const;
|
||||
QString getGameNameFilter() const;
|
||||
void setGameNameFilter(const QString &_gameNameFilter);
|
||||
QString getCreatorNameFilter() const;
|
||||
QStringList getCreatorNameFilters() const;
|
||||
void setCreatorNameFilter(const QString &_creatorNameFilter);
|
||||
QSet<int> getGameTypeFilter() const;
|
||||
void setGameTypeFilter(const QSet<int> &_gameTypeFilter);
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
|
|||
|
||||
if (deckLoader->getDeckList()->loadFromStream_Plain(stream, true)) {
|
||||
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
||||
deckLoader->resolveSetNameAndNumberToProviderID();
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(deckLoader->getDeckList());
|
||||
} else {
|
||||
deckLoader->clearSetNamesAndNumbers();
|
||||
DeckLoader::clearSetNamesAndNumbers(deckLoader->getDeckList());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -154,17 +154,17 @@ DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckLoader &deckList, bool
|
|||
* @param addComments Whether to add annotations
|
||||
* @return A QString
|
||||
*/
|
||||
static QString deckListToString(const DeckLoader *deckList, bool addComments)
|
||||
static QString deckListToString(const DeckList *deckList, bool addComments)
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
deckList->saveToStream_Plain(stream, addComments);
|
||||
DeckLoader::saveToStream_Plain(stream, deckList, addComments);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void DlgEditDeckInClipboard::actRefresh()
|
||||
{
|
||||
setText(deckListToString(deckLoader, annotated));
|
||||
setText(deckListToString(deckLoader->getDeckList(), annotated));
|
||||
}
|
||||
|
||||
void DlgEditDeckInClipboard::actOK()
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ void DlgLoadDeckFromWebsite::accept()
|
|||
DeckLoader *loader = new DeckLoader(this);
|
||||
QTextStream stream(&deckText);
|
||||
loader->getDeckList()->loadFromStream_Plain(stream, false);
|
||||
loader->resolveSetNameAndNumberToProviderID();
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(loader->getDeckList());
|
||||
deck = loader;
|
||||
|
||||
QDialog::accept();
|
||||
|
|
|
|||
|
|
@ -162,14 +162,14 @@ void DlgSelectSetForCards::actOK()
|
|||
|
||||
void DlgSelectSetForCards::actClear()
|
||||
{
|
||||
qobject_cast<DeckLoader *>(model->getDeckList())->clearSetNamesAndNumbers();
|
||||
DeckLoader::clearSetNamesAndNumbers(model->getDeckList());
|
||||
accept();
|
||||
}
|
||||
|
||||
void DlgSelectSetForCards::actSetAllToPreferred()
|
||||
{
|
||||
qobject_cast<DeckLoader *>(model->getDeckList())->clearSetNamesAndNumbers();
|
||||
qobject_cast<DeckLoader *>(model->getDeckList())->setProviderIdToPreferredPrinting();
|
||||
DeckLoader::clearSetNamesAndNumbers(model->getDeckList());
|
||||
DeckLoader::setProviderIdToPreferredPrinting(model->getDeckList());
|
||||
accept();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ QGroupBox *HomeWidget::createButtons()
|
|||
boxLayout->addSpacing(25);
|
||||
|
||||
connectButton = new HomeStyledButton("Connect/Play", gradientColors);
|
||||
boxLayout->addWidget(connectButton, 1);
|
||||
boxLayout->addWidget(connectButton);
|
||||
|
||||
auto visualDeckEditorButton = new HomeStyledButton(tr("Create New Deck"), gradientColors);
|
||||
connect(visualDeckEditorButton, &QPushButton::clicked, tabSupervisor,
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ GameSelector::GameSelector(AbstractClient *_client,
|
|||
|
||||
gameListView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
|
||||
if (showFilters && restoresettings) {
|
||||
quickFilterToolBar = new GameSelectorQuickFilterToolBar(this, tabSupervisor, gameListProxyModel, gameTypeMap);
|
||||
} else {
|
||||
quickFilterToolBar = nullptr;
|
||||
}
|
||||
|
||||
filterButton = new QPushButton;
|
||||
filterButton->setIcon(QPixmap("theme:icons/search"));
|
||||
connect(filterButton, &QPushButton::clicked, this, &GameSelector::actSetFilter);
|
||||
|
|
@ -92,7 +98,9 @@ GameSelector::GameSelector(AbstractClient *_client,
|
|||
createButton = nullptr;
|
||||
}
|
||||
joinButton = new QPushButton;
|
||||
joinAsJudgeButton = new QPushButton;
|
||||
spectateButton = new QPushButton;
|
||||
joinAsJudgeSpectatorButton = new QPushButton;
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
if (showFilters) {
|
||||
|
|
@ -103,10 +111,23 @@ GameSelector::GameSelector(AbstractClient *_client,
|
|||
if (room)
|
||||
buttonLayout->addWidget(createButton);
|
||||
buttonLayout->addWidget(joinButton);
|
||||
if (tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
||||
buttonLayout->addWidget(joinAsJudgeButton);
|
||||
} else {
|
||||
joinAsJudgeButton->setHidden(true);
|
||||
}
|
||||
buttonLayout->addWidget(spectateButton);
|
||||
if (tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
||||
buttonLayout->addWidget(joinAsJudgeSpectatorButton);
|
||||
} else {
|
||||
joinAsJudgeSpectatorButton->setHidden(true);
|
||||
}
|
||||
buttonLayout->setAlignment(Qt::AlignTop);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
if (showFilters && restoresettings) {
|
||||
mainLayout->addWidget(quickFilterToolBar);
|
||||
}
|
||||
mainLayout->addWidget(gameListView);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
|
||||
|
|
@ -117,7 +138,9 @@ GameSelector::GameSelector(AbstractClient *_client,
|
|||
setMinimumHeight(200);
|
||||
|
||||
connect(joinButton, &QPushButton::clicked, this, &GameSelector::actJoin);
|
||||
connect(spectateButton, &QPushButton::clicked, this, &GameSelector::actSpectate);
|
||||
connect(joinAsJudgeButton, &QPushButton::clicked, this, &GameSelector::actJoinAsJudge);
|
||||
connect(spectateButton, &QPushButton::clicked, this, &GameSelector::actJoinAsSpectator);
|
||||
connect(joinAsJudgeSpectatorButton, &QPushButton::clicked, this, &GameSelector::actJoinAsJudgeSpectator);
|
||||
connect(gameListView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
&GameSelector::actSelectedGameChanged);
|
||||
connect(gameListView, &QTreeView::activated, this, &GameSelector::actJoin);
|
||||
|
|
@ -158,7 +181,7 @@ void GameSelector::actSetFilter()
|
|||
gameListProxyModel->setGameFilters(
|
||||
dlg.getHideBuddiesOnlyGames(), dlg.getHideIgnoredUserGames(), dlg.getHideFullGames(),
|
||||
dlg.getHideGamesThatStarted(), dlg.getHidePasswordProtectedGames(), dlg.getHideNotBuddyCreatedGames(),
|
||||
dlg.getHideOpenDecklistGames(), dlg.getGameNameFilter(), dlg.getCreatorNameFilter(), dlg.getGameTypeFilter(),
|
||||
dlg.getHideOpenDecklistGames(), dlg.getGameNameFilter(), dlg.getCreatorNameFilters(), dlg.getGameTypeFilter(),
|
||||
dlg.getMaxPlayersFilterMin(), dlg.getMaxPlayersFilterMax(), dlg.getMaxGameAge(),
|
||||
dlg.getShowOnlyIfSpectatorsCanWatch(), dlg.getShowSpectatorPasswordProtected(),
|
||||
dlg.getShowOnlyIfSpectatorsCanChat(), dlg.getShowOnlyIfSpectatorsCanSeeHands());
|
||||
|
|
@ -238,12 +261,30 @@ void GameSelector::checkResponse(const Response &response)
|
|||
|
||||
void GameSelector::actJoin()
|
||||
{
|
||||
return joinGame(false);
|
||||
joinGame();
|
||||
}
|
||||
|
||||
void GameSelector::actSpectate()
|
||||
void GameSelector::actJoinAsJudge()
|
||||
{
|
||||
return joinGame(true);
|
||||
if (!(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsJudge)) {
|
||||
joinGame();
|
||||
} else {
|
||||
joinGame(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSelector::actJoinAsSpectator()
|
||||
{
|
||||
joinGame(true);
|
||||
}
|
||||
|
||||
void GameSelector::actJoinAsJudgeSpectator()
|
||||
{
|
||||
if (!(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsJudge)) {
|
||||
joinGame(true);
|
||||
} else {
|
||||
joinGame(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSelector::customContextMenu(const QPoint &point)
|
||||
|
|
@ -257,7 +298,7 @@ void GameSelector::customContextMenu(const QPoint &point)
|
|||
connect(&joinGame, &QAction::triggered, this, &GameSelector::actJoin);
|
||||
|
||||
QAction spectateGame(tr("Spectate Game"));
|
||||
connect(&spectateGame, &QAction::triggered, this, &GameSelector::actSpectate);
|
||||
connect(&spectateGame, &QAction::triggered, this, &GameSelector::actJoinAsSpectator);
|
||||
|
||||
QAction getGameInfo(tr("Game Information"));
|
||||
connect(&getGameInfo, &QAction::triggered, this, [=, this]() {
|
||||
|
|
@ -270,12 +311,25 @@ void GameSelector::customContextMenu(const QPoint &point)
|
|||
|
||||
QMenu menu;
|
||||
menu.addAction(&joinGame);
|
||||
|
||||
if (tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsJudge) {
|
||||
QAction joinGameAsJudge(tr("Join Game as Judge"));
|
||||
connect(&joinGameAsJudge, &QAction::triggered, this, &GameSelector::actJoinAsJudge);
|
||||
|
||||
menu.addAction(&joinGameAsJudge);
|
||||
|
||||
QAction spectateGameAsJudge(tr("Spectate Game as Judge"));
|
||||
connect(&spectateGameAsJudge, &QAction::triggered, this, &GameSelector::actJoinAsJudgeSpectator);
|
||||
|
||||
menu.addAction(&spectateGameAsJudge);
|
||||
}
|
||||
|
||||
menu.addAction(&spectateGame);
|
||||
menu.addAction(&getGameInfo);
|
||||
menu.exec(gameListView->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameSelector::joinGame(const bool isSpectator)
|
||||
void GameSelector::joinGame(const bool asSpectator, const bool asJudge)
|
||||
{
|
||||
QModelIndex ind = gameListView->currentIndex();
|
||||
if (!ind.isValid()) {
|
||||
|
|
@ -287,7 +341,7 @@ void GameSelector::joinGame(const bool isSpectator)
|
|||
return;
|
||||
}
|
||||
|
||||
bool spectator = isSpectator || game.player_count() == game.max_players();
|
||||
bool spectator = asSpectator || game.player_count() == game.max_players();
|
||||
|
||||
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
|
||||
QString password;
|
||||
|
|
@ -304,7 +358,7 @@ void GameSelector::joinGame(const bool isSpectator)
|
|||
cmd.set_password(password.toStdString());
|
||||
cmd.set_spectator(spectator);
|
||||
cmd.set_override_restrictions(overrideRestrictions);
|
||||
cmd.set_join_as_judge((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0);
|
||||
cmd.set_join_as_judge(asJudge);
|
||||
|
||||
TabRoom *r = tabSupervisor->getRoomTabs().value(game.room_id());
|
||||
if (!r) {
|
||||
|
|
@ -356,7 +410,9 @@ void GameSelector::retranslateUi()
|
|||
if (createButton)
|
||||
createButton->setText(tr("C&reate"));
|
||||
joinButton->setText(tr("&Join"));
|
||||
joinAsJudgeButton->setText(tr("Join as judge"));
|
||||
spectateButton->setText(tr("J&oin as spectator"));
|
||||
joinAsJudgeSpectatorButton->setText(tr("Join as judge spectator"));
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
/**
|
||||
* @file game_selector.h
|
||||
* @ingroup Lobby
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef GAMESELECTOR_H
|
||||
#define GAMESELECTOR_H
|
||||
|
||||
#include "game_selector_quick_filter_toolbar.h"
|
||||
#include "game_type_map.h"
|
||||
|
||||
#include <QGroupBox>
|
||||
|
|
@ -26,46 +21,167 @@ class TabRoom;
|
|||
class ServerInfo_Game;
|
||||
class Response;
|
||||
|
||||
/**
|
||||
* @class GameSelector
|
||||
* @ingroup Lobby
|
||||
* @brief Provides a widget for displaying, filtering, joining, spectating, and creating games in a room.
|
||||
*
|
||||
* The GameSelector displays all available games in a QTreeView. It supports filtering,
|
||||
* creating, joining, spectating, and viewing game details. Integrates with TabSupervisor
|
||||
* and TabRoom for room and game management.
|
||||
*/
|
||||
class GameSelector : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
/**
|
||||
* @brief Opens a dialog to set filters for the game list.
|
||||
*
|
||||
* Updates the proxy model with selected filter parameters and refreshes the displayed game list.
|
||||
*/
|
||||
void actSetFilter();
|
||||
|
||||
/**
|
||||
* @brief Clears all filters applied to the game list.
|
||||
*
|
||||
* Resets the proxy model to show all games.
|
||||
*/
|
||||
void actClearFilter();
|
||||
|
||||
/**
|
||||
* @brief Opens the dialog to create a new game in the current room.
|
||||
*/
|
||||
void actCreate();
|
||||
|
||||
/**
|
||||
* @brief Joins the currently selected game as a player.
|
||||
*/
|
||||
void actJoin();
|
||||
void actSpectate();
|
||||
/**
|
||||
* @brief Joins the currently selected game as a judge.
|
||||
*/
|
||||
void actJoinAsJudge();
|
||||
|
||||
/**
|
||||
* @brief Joins the currently selected game as a spectator.
|
||||
*/
|
||||
void actJoinAsSpectator();
|
||||
void actJoinAsJudgeSpectator();
|
||||
|
||||
/**
|
||||
* @brief Shows the custom context menu for a game when right-clicked.
|
||||
* @param point The point at which the context menu is requested.
|
||||
*/
|
||||
void customContextMenu(const QPoint &point);
|
||||
|
||||
/**
|
||||
* @brief Slot called when the selected game changes.
|
||||
* @param current The currently selected index.
|
||||
* @param previous The previously selected index.
|
||||
*
|
||||
* Updates the enabled/disabled state of buttons depending on the selected game.
|
||||
*/
|
||||
void actSelectedGameChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
/**
|
||||
* @brief Processes server responses for join or spectate commands.
|
||||
* @param response The response from the server.
|
||||
*
|
||||
* Displays error messages for failed join/spectate attempts.
|
||||
*/
|
||||
void checkResponse(const Response &response);
|
||||
|
||||
/**
|
||||
* @brief Refreshes the game list when the ignore list is received from the server.
|
||||
* @param _ignoreList The list of users being ignored.
|
||||
*/
|
||||
void ignoreListReceived(const QList<ServerInfo_User> &_ignoreList);
|
||||
|
||||
/**
|
||||
* @brief Processes events where a user is added to a list (e.g., ignore or buddy).
|
||||
* @param event The event information.
|
||||
*/
|
||||
void processAddToListEvent(const Event_AddToList &event);
|
||||
|
||||
/**
|
||||
* @brief Processes events where a user is removed from a list (e.g., ignore or buddy).
|
||||
* @param event The event information.
|
||||
*/
|
||||
void processRemoveFromListEvent(const Event_RemoveFromList &event);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief Emitted when a game has been successfully joined.
|
||||
* @param gameId The ID of the joined game.
|
||||
*/
|
||||
void gameJoined(int gameId);
|
||||
|
||||
private:
|
||||
AbstractClient *client;
|
||||
TabSupervisor *tabSupervisor;
|
||||
TabRoom *room;
|
||||
AbstractClient *client; /**< The network client used to communicate with the server. */
|
||||
TabSupervisor *tabSupervisor; /**< Reference to TabSupervisor for managing tabs and rooms. */
|
||||
TabRoom *room; /**< The current room. */
|
||||
|
||||
QTreeView *gameListView;
|
||||
GamesModel *gameListModel;
|
||||
GamesProxyModel *gameListProxyModel;
|
||||
QPushButton *filterButton, *clearFilterButton, *createButton, *joinButton, *spectateButton;
|
||||
const bool showFilters;
|
||||
GameTypeMap gameTypeMap;
|
||||
QTreeView *gameListView; /**< View widget for displaying the game list. */
|
||||
GamesModel *gameListModel; /**< Model containing all games. */
|
||||
GamesProxyModel *gameListProxyModel; /**< Proxy model for filtering and sorting the game list. */
|
||||
|
||||
GameSelectorQuickFilterToolBar *quickFilterToolBar;
|
||||
|
||||
QPushButton *filterButton; /**< Button to open the filter dialog. */
|
||||
QPushButton *clearFilterButton; /**< Button to clear active filters. */
|
||||
QPushButton *createButton; /**< Button to create a new game (only if room is set). */
|
||||
QPushButton *joinButton; /**< Button to join the selected game. */
|
||||
QPushButton *joinAsJudgeButton; /**< Button to join the selected game as a judge. */
|
||||
QPushButton *spectateButton; /**< Button to spectate the selected game. */
|
||||
QPushButton *joinAsJudgeSpectatorButton; /**< Button to join the selected game as a spectating judge. */
|
||||
|
||||
const bool showFilters; /**< Determines whether filter buttons are displayed. */
|
||||
GameTypeMap gameTypeMap; /**< Mapping of game types for the current room. */
|
||||
|
||||
/**
|
||||
* @brief Updates the widget title to reflect the current number of displayed games.
|
||||
*
|
||||
* Shows the number of visible games versus total games if filters are enabled.
|
||||
*/
|
||||
void updateTitle();
|
||||
|
||||
/**
|
||||
* @brief Disables create/join/spectate buttons.
|
||||
*/
|
||||
void disableButtons();
|
||||
|
||||
/**
|
||||
* @brief Enables buttons for the currently selected game.
|
||||
*/
|
||||
void enableButtons();
|
||||
|
||||
/**
|
||||
* @brief Enables buttons for a specific game index.
|
||||
* @param current The index of the currently selected game.
|
||||
*/
|
||||
void enableButtonsForIndex(const QModelIndex ¤t);
|
||||
void joinGame(const bool isSpectator);
|
||||
|
||||
/**
|
||||
* @brief Performs the join or spectate action for the currently selected game.
|
||||
* @param asSpectator True to join as a spectator, false to join as a player.
|
||||
* @param asJudge True to join as a judge, false to join as a player.
|
||||
*
|
||||
* Handles password prompts, overrides, and sending the join command to the server.
|
||||
*/
|
||||
void joinGame(bool asSpectator = false, bool asJudge = false);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a GameSelector widget.
|
||||
* @param _client The network client used to communicate with the server.
|
||||
* @param _tabSupervisor Reference to TabSupervisor for managing tabs and rooms.
|
||||
* @param _room Pointer to the current room; nullptr if no room is selected.
|
||||
* @param _rooms Map of room IDs to room names.
|
||||
* @param _gameTypes Map of room IDs to their available game types.
|
||||
* @param restoresettings Whether to restore filter settings from previous sessions.
|
||||
* @param _showfilters Whether to display filter buttons.
|
||||
* @param parent Parent QWidget.
|
||||
*/
|
||||
GameSelector(AbstractClient *_client,
|
||||
TabSupervisor *_tabSupervisor,
|
||||
TabRoom *_room,
|
||||
|
|
@ -74,7 +190,16 @@ public:
|
|||
const bool restoresettings,
|
||||
const bool _showfilters,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Updates UI text for translation/localization.
|
||||
*/
|
||||
void retranslateUi();
|
||||
|
||||
/**
|
||||
* @brief Updates or adds a game entry in the list.
|
||||
* @param info The ServerInfo_Game object containing information about the game to update.
|
||||
*/
|
||||
void processGameInfo(const ServerInfo_Game &info);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
#include "game_selector_quick_filter_toolbar.h"
|
||||
|
||||
#include "games_model.h"
|
||||
#include "user/user_list_manager.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
GameSelectorQuickFilterToolBar::GameSelectorQuickFilterToolBar(QWidget *parent,
|
||||
TabSupervisor *_tabSupervisor,
|
||||
GamesProxyModel *_model,
|
||||
const QMap<int, QString> &allGameTypes)
|
||||
: QWidget(parent), tabSupervisor(_tabSupervisor), model(_model)
|
||||
{
|
||||
mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(5);
|
||||
|
||||
searchBar = new QLineEdit(this);
|
||||
searchBar->setText(model->getCreatorNameFilters().join(", "));
|
||||
connect(searchBar, &QLineEdit::textChanged, this, [this](const QString &text) { model->setGameNameFilter(text); });
|
||||
|
||||
hideGamesNotCreatedByBuddiesCheckBox = new QCheckBox(this);
|
||||
hideGamesNotCreatedByBuddiesCheckBox->setChecked(model->getHideBuddiesOnlyGames());
|
||||
connect(hideGamesNotCreatedByBuddiesCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
if (checked) {
|
||||
QStringList buddyNames;
|
||||
for (auto buddy : tabSupervisor->getUserListManager()->getBuddyList().values()) {
|
||||
buddyNames << QString::fromStdString(buddy.name());
|
||||
}
|
||||
model->setCreatorNameFilters(buddyNames);
|
||||
} else {
|
||||
model->setCreatorNameFilters({});
|
||||
}
|
||||
});
|
||||
|
||||
hideFullGamesCheckBox = new QCheckBox(this);
|
||||
hideFullGamesCheckBox->setChecked(model->getHideFullGames());
|
||||
connect(hideFullGamesCheckBox, &QCheckBox::toggled, this,
|
||||
[this](bool checked) { model->setHideFullGames(checked); });
|
||||
|
||||
hideStartedGamesCheckBox = new QCheckBox(this);
|
||||
hideStartedGamesCheckBox->setChecked(model->getHideGamesThatStarted());
|
||||
connect(hideStartedGamesCheckBox, &QCheckBox::toggled, this,
|
||||
[this](bool checked) { model->setHideGamesThatStarted(checked); });
|
||||
|
||||
filterToFormatComboBox = new QComboBox(this);
|
||||
|
||||
// Add a "No filter" / "All types" option first
|
||||
filterToFormatComboBox->addItem(tr("All types"), QVariant()); // empty QVariant = no filter
|
||||
|
||||
QMapIterator<int, QString> i(allGameTypes);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
filterToFormatComboBox->addItem(i.value(), i.key()); // text = name, data = type ID
|
||||
}
|
||||
|
||||
QSet<int> currentTypes = model->getGameTypeFilter();
|
||||
if (currentTypes.size() == 1) {
|
||||
int typeId = *currentTypes.begin();
|
||||
int index = filterToFormatComboBox->findData(typeId);
|
||||
if (index >= 0)
|
||||
filterToFormatComboBox->setCurrentIndex(index);
|
||||
} else {
|
||||
filterToFormatComboBox->setCurrentIndex(0); // "All types" by default
|
||||
}
|
||||
|
||||
// Update proxy model on selection change
|
||||
connect(filterToFormatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
QVariant data = filterToFormatComboBox->itemData(index);
|
||||
if (!data.isValid()) {
|
||||
model->setGameTypeFilter({}); // empty = no filter
|
||||
} else {
|
||||
int typeId = data.toInt();
|
||||
model->setGameTypeFilter({typeId});
|
||||
}
|
||||
});
|
||||
|
||||
hideGamesNotCreatedByBuddiesCheckBox->setMinimumSize(20, 20);
|
||||
hideFullGamesCheckBox->setMinimumSize(20, 20);
|
||||
hideStartedGamesCheckBox->setMinimumSize(20, 20);
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
mainLayout->setSpacing(6);
|
||||
#endif
|
||||
|
||||
mainLayout->addWidget(searchBar);
|
||||
mainLayout->addWidget(filterToFormatComboBox);
|
||||
mainLayout->addWidget(hideGamesNotCreatedByBuddiesCheckBox);
|
||||
mainLayout->addSpacing(5);
|
||||
mainLayout->addWidget(hideFullGamesCheckBox);
|
||||
mainLayout->addSpacing(5);
|
||||
mainLayout->addWidget(hideStartedGamesCheckBox);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void GameSelectorQuickFilterToolBar::retranslateUi()
|
||||
{
|
||||
searchBar->setPlaceholderText(tr("Filter by game name..."));
|
||||
filterToFormatComboBox->setToolTip(tr("Filter by game type/format"));
|
||||
hideGamesNotCreatedByBuddiesCheckBox->setText(tr("Hide games not created by buddies"));
|
||||
hideFullGamesCheckBox->setText(tr("Hide full games"));
|
||||
hideStartedGamesCheckBox->setText(tr("Hide started games"));
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef COCKATRICE_GAME_SELECTOR_QUICK_FILTER_TOOLBAR_H
|
||||
#define COCKATRICE_GAME_SELECTOR_QUICK_FILTER_TOOLBAR_H
|
||||
|
||||
#include "../tabs/tab_supervisor.h"
|
||||
#include "games_model.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QWidget>
|
||||
|
||||
class GameSelectorQuickFilterToolBar : public QWidget
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GameSelectorQuickFilterToolBar(QWidget *parent,
|
||||
TabSupervisor *tabSupervisor,
|
||||
GamesProxyModel *model,
|
||||
const QMap<int, QString> &allGameTypes);
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
TabSupervisor *tabSupervisor;
|
||||
GamesProxyModel *model;
|
||||
|
||||
QHBoxLayout *mainLayout;
|
||||
|
||||
QLineEdit *searchBar;
|
||||
QCheckBox *hideGamesNotCreatedByBuddiesCheckBox;
|
||||
QCheckBox *hideFullGamesCheckBox;
|
||||
QCheckBox *hideStartedGamesCheckBox;
|
||||
QComboBox *filterToFormatComboBox;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_GAME_SELECTOR_QUICK_FILTER_TOOLBAR_H
|
||||
|
|
@ -294,7 +294,7 @@ void GamesProxyModel::setGameFilters(bool _hideBuddiesOnlyGames,
|
|||
bool _hideNotBuddyCreatedGames,
|
||||
bool _hideOpenDecklistGames,
|
||||
const QString &_gameNameFilter,
|
||||
const QString &_creatorNameFilter,
|
||||
const QStringList &_creatorNameFilters,
|
||||
const QSet<int> &_gameTypeFilter,
|
||||
int _maxPlayersFilterMin,
|
||||
int _maxPlayersFilterMax,
|
||||
|
|
@ -315,7 +315,7 @@ void GamesProxyModel::setGameFilters(bool _hideBuddiesOnlyGames,
|
|||
hideNotBuddyCreatedGames = _hideNotBuddyCreatedGames;
|
||||
hideOpenDecklistGames = _hideOpenDecklistGames;
|
||||
gameNameFilter = _gameNameFilter;
|
||||
creatorNameFilter = _creatorNameFilter;
|
||||
creatorNameFilters = _creatorNameFilters;
|
||||
gameTypeFilter = _gameTypeFilter;
|
||||
maxPlayersFilterMin = _maxPlayersFilterMin;
|
||||
maxPlayersFilterMax = _maxPlayersFilterMax;
|
||||
|
|
@ -348,15 +348,15 @@ int GamesProxyModel::getNumFilteredGames() const
|
|||
|
||||
void GamesProxyModel::resetFilterParameters()
|
||||
{
|
||||
setGameFilters(false, false, false, false, false, false, false, QString(), QString(), {}, DEFAULT_MAX_PLAYERS_MIN,
|
||||
DEFAULT_MAX_PLAYERS_MAX, DEFAULT_MAX_GAME_AGE, false, false, false, false);
|
||||
setGameFilters(false, false, false, false, false, false, false, QString(), QStringList(), {},
|
||||
DEFAULT_MAX_PLAYERS_MIN, DEFAULT_MAX_PLAYERS_MAX, DEFAULT_MAX_GAME_AGE, false, false, false, false);
|
||||
}
|
||||
|
||||
bool GamesProxyModel::areFilterParametersSetToDefaults() const
|
||||
{
|
||||
return !hideFullGames && !hideGamesThatStarted && !hidePasswordProtectedGames && !hideBuddiesOnlyGames &&
|
||||
!hideOpenDecklistGames && !hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() &&
|
||||
creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
|
||||
creatorNameFilters.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
|
||||
maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE &&
|
||||
!showOnlyIfSpectatorsCanWatch && !showSpectatorPasswordProtected && !showOnlyIfSpectatorsCanChat &&
|
||||
!showOnlyIfSpectatorsCanSeeHands;
|
||||
|
|
@ -379,7 +379,7 @@ void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameType
|
|||
gameFilters.isHideFullGames(), gameFilters.isHideGamesThatStarted(),
|
||||
gameFilters.isHidePasswordProtectedGames(), gameFilters.isHideNotBuddyCreatedGames(),
|
||||
gameFilters.isHideOpenDecklistGames(), gameFilters.getGameNameFilter(),
|
||||
gameFilters.getCreatorNameFilter(), newGameTypeFilter, gameFilters.getMinPlayers(),
|
||||
gameFilters.getCreatorNameFilters(), newGameTypeFilter, gameFilters.getMinPlayers(),
|
||||
gameFilters.getMaxPlayers(), gameFilters.getMaxGameAge(),
|
||||
gameFilters.isShowOnlyIfSpectatorsCanWatch(), gameFilters.isShowSpectatorPasswordProtected(),
|
||||
gameFilters.isShowOnlyIfSpectatorsCanChat(), gameFilters.isShowOnlyIfSpectatorsCanSeeHands());
|
||||
|
|
@ -396,7 +396,7 @@ void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameType
|
|||
gameFilters.setHideNotBuddyCreatedGames(hideNotBuddyCreatedGames);
|
||||
gameFilters.setHideOpenDecklistGames(hideOpenDecklistGames);
|
||||
gameFilters.setGameNameFilter(gameNameFilter);
|
||||
gameFilters.setCreatorNameFilter(creatorNameFilter);
|
||||
gameFilters.setCreatorNameFilters(creatorNameFilters);
|
||||
|
||||
QMapIterator<int, QString> gameTypeIterator(allGameTypes);
|
||||
while (gameTypeIterator.hasNext()) {
|
||||
|
|
@ -459,9 +459,17 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
|||
if (!gameNameFilter.isEmpty())
|
||||
if (!QString::fromStdString(game.description()).contains(gameNameFilter, Qt::CaseInsensitive))
|
||||
return false;
|
||||
if (!creatorNameFilter.isEmpty())
|
||||
if (!QString::fromStdString(game.creator_info().name()).contains(creatorNameFilter, Qt::CaseInsensitive))
|
||||
if (!creatorNameFilters.isEmpty()) {
|
||||
bool found = false;
|
||||
for (const auto &createNameFilter : creatorNameFilters) {
|
||||
if (QString::fromStdString(game.creator_info().name()).contains(createNameFilter, Qt::CaseInsensitive)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QSet<int> gameTypes;
|
||||
for (int i = 0; i < game.game_types_size(); ++i)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/**
|
||||
* @file games_model.h
|
||||
* @ingroup Lobby
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef GAMESMODEL_H
|
||||
#define GAMESMODEL_H
|
||||
|
||||
|
|
@ -19,60 +13,107 @@
|
|||
|
||||
class UserListProxy;
|
||||
|
||||
/**
|
||||
* @class GamesModel
|
||||
* @ingroup Lobby
|
||||
* @brief Model storing all available games for display in a QTreeView or QTableView.
|
||||
*
|
||||
* Provides access to game information, supports sorting by different columns,
|
||||
* and updates when new game data is received from the server.
|
||||
*/
|
||||
class GamesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QList<ServerInfo_Game> gameList;
|
||||
QMap<int, QString> rooms;
|
||||
QMap<int, GameTypeMap> gameTypes;
|
||||
QList<ServerInfo_Game> gameList; /**< List of games currently displayed. */
|
||||
QMap<int, QString> rooms; /**< Map of room IDs to room names. */
|
||||
QMap<int, GameTypeMap> gameTypes; /**< Map of room IDs to available game types. */
|
||||
|
||||
static const int NUM_COLS = 8;
|
||||
static const int NUM_COLS = 8; /**< Number of columns in the table. */
|
||||
|
||||
public:
|
||||
static const int SORT_ROLE = Qt::UserRole + 1;
|
||||
static const int SORT_ROLE = Qt::UserRole + 1; /**< Role used for sorting. */
|
||||
|
||||
/**
|
||||
* @brief Constructs a GamesModel.
|
||||
* @param _rooms Mapping of room IDs to room names.
|
||||
* @param _gameTypes Mapping of room IDs to their available game types.
|
||||
* @param parent Parent QObject.
|
||||
*/
|
||||
GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
return parent.isValid() ? 0 : gameList.size();
|
||||
}
|
||||
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override
|
||||
{
|
||||
return NUM_COLS;
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
/**
|
||||
* @brief Formats the game creation time into a human-readable string.
|
||||
* @param secs Number of seconds since the game started.
|
||||
* @return Short string representing game age (e.g., "new", ">5 min", ">2 hr").
|
||||
*/
|
||||
static const QString getGameCreatedString(const int secs);
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to a specific game by row index.
|
||||
* @param row Row index in the table.
|
||||
* @return Reference to the ServerInfo_Game at the given row.
|
||||
*/
|
||||
const ServerInfo_Game &getGame(int row);
|
||||
|
||||
/**
|
||||
* Update game list with a (possibly new) game.
|
||||
* @brief Updates the game list with a new or updated game.
|
||||
* @param game The ServerInfo_Game object to add or update.
|
||||
*/
|
||||
void updateGameList(const ServerInfo_Game &game);
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the room column.
|
||||
*/
|
||||
int roomColIndex()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the index of the start time column.
|
||||
*/
|
||||
int startTimeColIndex()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the map of game types per room.
|
||||
*/
|
||||
const QMap<int, GameTypeMap> &getGameTypes()
|
||||
{
|
||||
return gameTypes;
|
||||
}
|
||||
};
|
||||
|
||||
class ServerInfo_User;
|
||||
|
||||
/**
|
||||
* @class GamesProxyModel
|
||||
* @ingroup Lobby
|
||||
* @brief Proxy model for filtering and sorting the GamesModel based on user preferences.
|
||||
*
|
||||
* Supports filtering games based on buddies-only, ignored users, password protection,
|
||||
* game types, creator, age, player count, and spectator permissions.
|
||||
*/
|
||||
class GamesProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
const UserListProxy *userListProxy;
|
||||
const UserListProxy *userListProxy; /**< Proxy for checking user ignore/buddy lists. */
|
||||
|
||||
// If adding any additional filters, make sure to update:
|
||||
// - GamesProxyModel()
|
||||
|
|
@ -88,16 +129,25 @@ private:
|
|||
bool hidePasswordProtectedGames;
|
||||
bool hideNotBuddyCreatedGames;
|
||||
bool hideOpenDecklistGames;
|
||||
QString gameNameFilter, creatorNameFilter;
|
||||
QString gameNameFilter;
|
||||
QStringList creatorNameFilters;
|
||||
QSet<int> gameTypeFilter;
|
||||
quint32 maxPlayersFilterMin, maxPlayersFilterMax;
|
||||
QTime maxGameAge;
|
||||
bool showOnlyIfSpectatorsCanWatch, showSpectatorPasswordProtected, showOnlyIfSpectatorsCanChat,
|
||||
showOnlyIfSpectatorsCanSeeHands;
|
||||
bool showOnlyIfSpectatorsCanWatch;
|
||||
bool showSpectatorPasswordProtected;
|
||||
bool showOnlyIfSpectatorsCanChat;
|
||||
bool showOnlyIfSpectatorsCanSeeHands;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a GamesProxyModel.
|
||||
* @param parent Parent QObject.
|
||||
* @param _userListProxy Proxy for accessing ignore/buddy lists.
|
||||
*/
|
||||
explicit GamesProxyModel(QObject *parent = nullptr, const UserListProxy *_userListProxy = nullptr);
|
||||
|
||||
// Getters for filter parameters
|
||||
bool getHideBuddiesOnlyGames() const
|
||||
{
|
||||
return hideBuddiesOnlyGames;
|
||||
|
|
@ -130,9 +180,9 @@ public:
|
|||
{
|
||||
return gameNameFilter;
|
||||
}
|
||||
QString getCreatorNameFilter() const
|
||||
QStringList getCreatorNameFilters() const
|
||||
{
|
||||
return creatorNameFilter;
|
||||
return creatorNameFilters;
|
||||
}
|
||||
QSet<int> getGameTypeFilter() const
|
||||
{
|
||||
|
|
@ -166,6 +216,10 @@ public:
|
|||
{
|
||||
return showOnlyIfSpectatorsCanSeeHands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets all game filters at once.
|
||||
*/
|
||||
void setGameFilters(bool _hideBuddiesOnlyGames,
|
||||
bool _hideIgnoredUserGames,
|
||||
bool _hideFullGames,
|
||||
|
|
@ -174,7 +228,7 @@ public:
|
|||
bool _hideNotBuddyCreatedGames,
|
||||
bool _hideOpenDecklistGames,
|
||||
const QString &_gameNameFilter,
|
||||
const QString &_creatorNameFilter,
|
||||
const QStringList &_creatorNameFilter,
|
||||
const QSet<int> &_gameTypeFilter,
|
||||
int _maxPlayersFilterMin,
|
||||
int _maxPlayersFilterMax,
|
||||
|
|
@ -184,11 +238,123 @@ public:
|
|||
bool _showOnlyIfSpectatorsCanChat,
|
||||
bool _showOnlyIfSpectatorsCanSeeHands);
|
||||
|
||||
// Individual setters
|
||||
void setHideBuddiesOnlyGames(bool value)
|
||||
{
|
||||
hideBuddiesOnlyGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setHideIgnoredUserGames(bool value)
|
||||
{
|
||||
hideIgnoredUserGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setHideFullGames(bool value)
|
||||
{
|
||||
hideFullGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setHideGamesThatStarted(bool value)
|
||||
{
|
||||
hideGamesThatStarted = value;
|
||||
refresh();
|
||||
}
|
||||
void setHidePasswordProtectedGames(bool value)
|
||||
{
|
||||
hidePasswordProtectedGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setHideNotBuddyCreatedGames(bool value)
|
||||
{
|
||||
hideNotBuddyCreatedGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setHideOpenDecklistGames(bool value)
|
||||
{
|
||||
hideOpenDecklistGames = value;
|
||||
refresh();
|
||||
}
|
||||
void setGameNameFilter(const QString &value)
|
||||
{
|
||||
gameNameFilter = value;
|
||||
refresh();
|
||||
}
|
||||
void setCreatorNameFilters(const QStringList &values)
|
||||
{
|
||||
creatorNameFilters = values;
|
||||
refresh();
|
||||
}
|
||||
void setGameTypeFilter(const QSet<int> &value)
|
||||
{
|
||||
gameTypeFilter = value;
|
||||
refresh();
|
||||
}
|
||||
void setMaxPlayersFilterMin(int value)
|
||||
{
|
||||
maxPlayersFilterMin = value;
|
||||
refresh();
|
||||
}
|
||||
void setMaxPlayersFilterMax(int value)
|
||||
{
|
||||
maxPlayersFilterMax = value;
|
||||
refresh();
|
||||
}
|
||||
void setMaxGameAge(const QTime &value)
|
||||
{
|
||||
maxGameAge = value;
|
||||
refresh();
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanWatch(bool value)
|
||||
{
|
||||
showOnlyIfSpectatorsCanWatch = value;
|
||||
refresh();
|
||||
}
|
||||
void setShowSpectatorPasswordProtected(bool value)
|
||||
{
|
||||
showSpectatorPasswordProtected = value;
|
||||
refresh();
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanChat(bool value)
|
||||
{
|
||||
showOnlyIfSpectatorsCanChat = value;
|
||||
refresh();
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanSeeHands(bool value)
|
||||
{
|
||||
showOnlyIfSpectatorsCanSeeHands = value;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of games filtered out by the current filter.
|
||||
*/
|
||||
int getNumFilteredGames() const;
|
||||
|
||||
/**
|
||||
* @brief Resets all filter parameters to default values.
|
||||
*/
|
||||
void resetFilterParameters();
|
||||
|
||||
/**
|
||||
* @brief Returns true if all filter parameters are set to their defaults.
|
||||
*/
|
||||
bool areFilterParametersSetToDefaults() const;
|
||||
|
||||
/**
|
||||
* @brief Loads filter parameters from persistent settings.
|
||||
* @param allGameTypes Mapping of all game types by room ID.
|
||||
*/
|
||||
void loadFilterParameters(const QMap<int, QString> &allGameTypes);
|
||||
|
||||
/**
|
||||
* @brief Saves filter parameters to persistent settings.
|
||||
* @param allGameTypes Mapping of all game types by room ID.
|
||||
*/
|
||||
void saveFilterParameters(const QMap<int, QString> &allGameTypes);
|
||||
|
||||
/**
|
||||
* @brief Refreshes the proxy model (re-applies filters).
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -510,32 +510,33 @@ void AbstractTabDeckEditor::actEditDeckInClipboardRaw()
|
|||
/** @brief Saves deck to clipboard with set info and annotation. */
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboard()
|
||||
{
|
||||
getDeckLoader()->saveToClipboard(true, true);
|
||||
DeckLoader::saveToClipboard(getDeckList(), true, true);
|
||||
}
|
||||
|
||||
/** @brief Saves deck to clipboard with annotation, without set info. */
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo()
|
||||
{
|
||||
getDeckLoader()->saveToClipboard(true, false);
|
||||
DeckLoader::saveToClipboard(getDeckList(), true, false);
|
||||
}
|
||||
|
||||
/** @brief Saves deck to clipboard without annotations, with set info. */
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
|
||||
{
|
||||
getDeckLoader()->saveToClipboard(false, true);
|
||||
DeckLoader::saveToClipboard(getDeckList(), false, true);
|
||||
}
|
||||
|
||||
/** @brief Saves deck to clipboard without annotations or set info. */
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
|
||||
{
|
||||
getDeckLoader()->saveToClipboard(false, false);
|
||||
DeckLoader::saveToClipboard(getDeckList(), false, false);
|
||||
}
|
||||
|
||||
/** @brief Prints the deck using a QPrintPreviewDialog. */
|
||||
void AbstractTabDeckEditor::actPrintDeck()
|
||||
{
|
||||
auto *dlg = new QPrintPreviewDialog(this);
|
||||
connect(dlg, &QPrintPreviewDialog::paintRequested, deckDockWidget->getDeckLoader(), &DeckLoader::printDeckList);
|
||||
connect(dlg, &QPrintPreviewDialog::paintRequested, this,
|
||||
[this](QPrinter *printer) { DeckLoader::printDeckList(printer, getDeckList()); });
|
||||
dlg->exec();
|
||||
}
|
||||
|
||||
|
|
@ -569,7 +570,7 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
|
|||
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
|
||||
{
|
||||
if (DeckLoader *const deck = getDeckLoader()) {
|
||||
QString decklistUrlString = deck->exportDeckToDecklist(website);
|
||||
QString decklistUrlString = deck->exportDeckToDecklist(getDeckList(), website);
|
||||
// Check to make sure the string isn't empty.
|
||||
if (decklistUrlString.isEmpty()) {
|
||||
// Show an error if the deck is empty, and return.
|
||||
|
|
|
|||
|
|
@ -326,13 +326,13 @@ QMenu *DeckPreviewWidget::createRightClickMenu()
|
|||
auto saveToClipboardMenu = menu->addMenu(tr("Save Deck to Clipboard"));
|
||||
|
||||
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
|
||||
[this] { deckLoader->saveToClipboard(true, true); });
|
||||
[this] { DeckLoader::saveToClipboard(deckLoader->getDeckList(), true, true); });
|
||||
connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this,
|
||||
[this] { deckLoader->saveToClipboard(true, false); });
|
||||
[this] { DeckLoader::saveToClipboard(deckLoader->getDeckList(), true, false); });
|
||||
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
|
||||
[this] { deckLoader->saveToClipboard(false, true); });
|
||||
[this] { DeckLoader::saveToClipboard(deckLoader->getDeckList(), false, true); });
|
||||
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this,
|
||||
[this] { deckLoader->saveToClipboard(false, false); });
|
||||
[this] { DeckLoader::saveToClipboard(deckLoader->getDeckList(), false, false); });
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,3 +3,5 @@
|
|||
@subpage editing_decks_classic
|
||||
|
||||
@subpage editing_decks_visual
|
||||
|
||||
@subpage editing_decks_printings
|
||||
|
|
@ -1 +1,122 @@
|
|||
@page editing_decks_printings Printing Selector
|
||||
|
||||
\image html printing_selector.png
|
||||
|
||||
# Purpose
|
||||
|
||||
The PrintingSelector allows editing the PrintingInfo associated with CardInfo%s contained in DeckList%s.
|
||||
|
||||
As described in PrintingInfo, a CardInfo can have different variations contained within the same or different CardSet%s.
|
||||
|
||||
PrintingSelector allows the user to choose a variation, as well as pinning a variation to be used as the preferred
|
||||
printing in all cases where the 'default' or 'most preferred' image should be shown.
|
||||
|
||||
# Pre-requisites (User Interface)
|
||||
|
||||
To use the printing selector, ensure that you are using the Post-ProviderID change behavior (Checkbox as shown in the
|
||||
image).
|
||||
|
||||
\image html printing_selector_pre_providerid.png
|
||||
|
||||
\attention This is the default behavior, unless you have explicitly changed it, in which case you will have seen a
|
||||
warning as follows. Once again, checking this box will *disable* the new behavior and revert you to the legacy system
|
||||
without the printing selector.
|
||||
|
||||
Disabling the printing selector:
|
||||
|
||||
\image html printing_selector_enable.png
|
||||
|
||||
Enabling the printing selector:
|
||||
|
||||
\image html printing_selector_disable.png
|
||||
|
||||
# Pre-requisites (Card Database)
|
||||
|
||||
The PrintingSelector requires each underlying CardInfo object to have a <set> entry with a *unique* providerID attribute
|
||||
for each variation that should be displayed.
|
||||
|
||||
Here is an example, that first defines three sets, and then the 'Ace of Hearts' card with three variations.
|
||||
|
||||
```xml
|
||||
<set rarity="common" uuid="00000000-0000-0000-0000-000000000033" num="51" muid="AH">PKR</set>
|
||||
<set rarity="common" uuid="00000000-0000-0000-0001-000000000033" num="51" muid="AHSTD">STD</set>
|
||||
<set rarity="common" uuid="00000000-0000-0000-0002-000000000033" num="51" muid="AHNBR">NBR</set>
|
||||
```
|
||||
|
||||
```xml
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<cockatrice_carddatabase version="4">
|
||||
<sets>
|
||||
<set>
|
||||
<name>PKR</name>
|
||||
<longname>Cockatrice Poker</longname>
|
||||
<settype>Custom</settype>
|
||||
<releasedate>2025-11-15</releasedate>
|
||||
</set>
|
||||
<set>
|
||||
<name>STD</name>
|
||||
<longname>Standard Poker</longname>
|
||||
<settype>core</settype>
|
||||
<releasedate>2025-11-14</releasedate>
|
||||
</set>
|
||||
<set>
|
||||
<name>NBR</name>
|
||||
<longname>Numbers</longname>
|
||||
<settype>core</settype>
|
||||
<releasedate>2025-11-14</releasedate>
|
||||
</set>
|
||||
</sets>
|
||||
<cards>
|
||||
<card>
|
||||
<name>Ace of Hearts</name>
|
||||
<text>Ace of Hearts</text>
|
||||
<prop>
|
||||
<layout>normal</layout>
|
||||
<side>front</side>
|
||||
<type>Ace</type>
|
||||
<maintype>Ace</maintype>
|
||||
<manacost>14</manacost>
|
||||
<cmc>14</cmc>
|
||||
<colors>H</colors>
|
||||
<coloridentity>H</coloridentity>
|
||||
<format-standard>legal</format-standard>
|
||||
</prop>
|
||||
<reverse-related>Joker</reverse-related>
|
||||
<token>0</token>
|
||||
<tablerow>1</tablerow>
|
||||
<cipt>0</cipt>
|
||||
<upsidedown>0</upsidedown>
|
||||
<set rarity="common" uuid="00000000-0000-0000-0000-000000000033" num="51" muid="AH">PKR</set>
|
||||
<set rarity="common" uuid="00000000-0000-0000-0001-000000000033" num="51" muid="AHSTD">STD</set>
|
||||
<set rarity="common" uuid="00000000-0000-0000-0002-000000000033" num="51" muid="AHNBR">NBR</set>
|
||||
</card>
|
||||
</cards>
|
||||
</cockatrice_carddatabase>
|
||||
```
|
||||
|
||||
# Using the Printing Selector
|
||||
|
||||
To use the PrintingSelector, first select a card in the DeckEditorDeckDockWidget:
|
||||
|
||||
\image html deck_dock_deck_list.png
|
||||
|
||||
You may add a variation to the mainboard by clicking the + and - buttons in the top row. The bottom row will add the
|
||||
variation to your sideboard.
|
||||
|
||||
\image html printing_selector.png
|
||||
|
||||
You can also right-click a variation to pin it, which will move it to the top of the variation list for easy access and
|
||||
additionally, use it as the default printing whenever the printing isn't explicitly specified (such as adding a card
|
||||
from the database in the deck editor).
|
||||
|
||||
Only one printing may be pinned at a time.
|
||||
|
||||
Additionally, the PrintingSelector offers a navigation bar at the bottom to navigate through cards in your deck, as well
|
||||
as an option to modify the variations of cards in bulk via the 'Bulk Selection' option.
|
||||
|
||||
\image html printing_selector_navigation.png
|
||||
|
||||
The search bar at the top may be used to filter the displayed variations and the cogwheel may be clicked to open up
|
||||
additional settings.
|
||||
|
||||
\image html printing_selector_options.png
|
||||
|
|
|
|||
BIN
doc/doxygen-images/printing_selector.png
Normal file
BIN
doc/doxygen-images/printing_selector.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
doc/doxygen-images/printing_selector_disable.png
Normal file
BIN
doc/doxygen-images/printing_selector_disable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
doc/doxygen-images/printing_selector_enable.png
Normal file
BIN
doc/doxygen-images/printing_selector_enable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
doc/doxygen-images/printing_selector_navigation.png
Normal file
BIN
doc/doxygen-images/printing_selector_navigation.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
BIN
doc/doxygen-images/printing_selector_options.png
Normal file
BIN
doc/doxygen-images/printing_selector_options.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
BIN
doc/doxygen-images/printing_selector_pre_providerid.png
Normal file
BIN
doc/doxygen-images/printing_selector_pre_providerid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
|
|
@ -26,13 +26,9 @@ CardInfo::CardInfo(const QString &_name,
|
|||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
SetToPrintingsMap _sets,
|
||||
bool _cipt,
|
||||
bool _landscapeOrientation,
|
||||
int _tableRow,
|
||||
bool _upsideDownArt)
|
||||
const UiAttributes _uiAttributes)
|
||||
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
|
||||
reverseRelatedCards(_reverseRelatedCards), setsToPrintings(std::move(_sets)), cipt(_cipt),
|
||||
landscapeOrientation(_landscapeOrientation), tableRow(_tableRow), upsideDownArt(_upsideDownArt)
|
||||
reverseRelatedCards(_reverseRelatedCards), setsToPrintings(std::move(_sets)), uiAttributes(_uiAttributes)
|
||||
{
|
||||
simpleName = CardInfo::simplifyName(name);
|
||||
|
||||
|
|
@ -41,8 +37,7 @@ CardInfo::CardInfo(const QString &_name,
|
|||
|
||||
CardInfoPtr CardInfo::newInstance(const QString &_name)
|
||||
{
|
||||
return newInstance(_name, QString(), false, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
|
||||
SetToPrintingsMap(), false, false, 0, false);
|
||||
return newInstance(_name, "", false, {}, {}, {}, {}, {});
|
||||
}
|
||||
|
||||
CardInfoPtr CardInfo::newInstance(const QString &_name,
|
||||
|
|
@ -52,13 +47,10 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
|
|||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
SetToPrintingsMap _sets,
|
||||
bool _cipt,
|
||||
bool _landscapeOrientation,
|
||||
int _tableRow,
|
||||
bool _upsideDownArt)
|
||||
const UiAttributes _uiAttributes)
|
||||
{
|
||||
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
|
||||
_sets, _cipt, _landscapeOrientation, _tableRow, _upsideDownArt));
|
||||
_sets, _uiAttributes));
|
||||
ptr->setSmartPointer(ptr);
|
||||
|
||||
for (const auto &printings : _sets) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,21 @@ class CardInfo : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @class CardInfo::UiAttributes
|
||||
* @ingroup Cards
|
||||
*
|
||||
* @brief Attributes of the card that affect display and game logic.
|
||||
*/
|
||||
struct UiAttributes
|
||||
{
|
||||
bool cipt = false; ///< Positioning flag used by UI.
|
||||
bool landscapeOrientation = false; ///< Orientation flag for rendering.
|
||||
int tableRow = 0; ///< Row index in a table or visual representation.
|
||||
bool upsideDownArt = false; ///< Whether artwork is flipped for visual purposes.
|
||||
};
|
||||
|
||||
private:
|
||||
/** @name Private Card Properties
|
||||
* @anchor PrivateCardProperties
|
||||
|
|
@ -63,10 +78,7 @@ private:
|
|||
QList<CardRelation *> reverseRelatedCardsToMe; ///< Cards that consider this card as related.
|
||||
SetToPrintingsMap setsToPrintings; ///< Mapping from set names to printing variations.
|
||||
QString setsNames; ///< Cached, human-readable list of set names.
|
||||
bool cipt; ///< Positioning flag used by UI.
|
||||
bool landscapeOrientation; ///< Orientation flag for rendering.
|
||||
int tableRow; ///< Row index in a table or visual representation.
|
||||
bool upsideDownArt; ///< Whether artwork is flipped for visual purposes.
|
||||
UiAttributes uiAttributes; ///< Attributes that affect display and game logic
|
||||
///@}
|
||||
|
||||
public:
|
||||
|
|
@ -80,10 +92,7 @@ public:
|
|||
* @param _relatedCards Forward references to related cards.
|
||||
* @param _reverseRelatedCards Backward references to related cards.
|
||||
* @param _sets Map of set names to printing information.
|
||||
* @param _cipt UI positioning flag.
|
||||
* @param _landscapeOrientation UI rendering orientation.
|
||||
* @param _tableRow Row index for table placement.
|
||||
* @param _upsideDownArt Whether the artwork should be displayed upside down.
|
||||
* @param _uiAttributes Attributes that affect display and game logic
|
||||
*/
|
||||
explicit CardInfo(const QString &_name,
|
||||
const QString &_text,
|
||||
|
|
@ -92,10 +101,7 @@ public:
|
|||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
SetToPrintingsMap _sets,
|
||||
bool _cipt,
|
||||
bool _landscapeOrientation,
|
||||
int _tableRow,
|
||||
bool _upsideDownArt);
|
||||
UiAttributes _uiAttributes);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor for CardInfo.
|
||||
|
|
@ -108,8 +114,7 @@ public:
|
|||
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), text(other.text),
|
||||
isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
|
||||
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
|
||||
setsToPrintings(other.setsToPrintings), setsNames(other.setsNames), cipt(other.cipt),
|
||||
landscapeOrientation(other.landscapeOrientation), tableRow(other.tableRow), upsideDownArt(other.upsideDownArt)
|
||||
setsToPrintings(other.setsToPrintings), setsNames(other.setsNames), uiAttributes(other.uiAttributes)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +138,7 @@ public:
|
|||
* @param _relatedCards Forward relationships.
|
||||
* @param _reverseRelatedCards Reverse relationships.
|
||||
* @param _sets Printing information per set.
|
||||
* @param _cipt UI positioning flag.
|
||||
* @param _landscapeOrientation UI rendering orientation.
|
||||
* @param _tableRow Row index for table placement.
|
||||
* @param _upsideDownArt Artwork orientation flag.
|
||||
* @param _uiAttributes Attributes that affect display and game logic
|
||||
* @return Shared pointer to the new CardInfo instance.
|
||||
*/
|
||||
static CardInfoPtr newInstance(const QString &_name,
|
||||
|
|
@ -146,10 +148,7 @@ public:
|
|||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
SetToPrintingsMap _sets,
|
||||
bool _cipt,
|
||||
bool _landscapeOrientation,
|
||||
int _tableRow,
|
||||
bool _upsideDownArt);
|
||||
UiAttributes _uiAttributes);
|
||||
|
||||
/**
|
||||
* @brief Clones the current CardInfo instance.
|
||||
|
|
@ -254,29 +253,14 @@ public:
|
|||
//@}
|
||||
|
||||
/** @name UI Positioning */ //@{
|
||||
bool getCipt() const
|
||||
const UiAttributes &getUiAttributes() const
|
||||
{
|
||||
return cipt;
|
||||
return uiAttributes;
|
||||
}
|
||||
bool getLandscapeOrientation() const
|
||||
{
|
||||
return landscapeOrientation;
|
||||
}
|
||||
int getTableRow() const
|
||||
{
|
||||
return tableRow;
|
||||
}
|
||||
void setTableRow(int _tableRow)
|
||||
{
|
||||
tableRow = _tableRow;
|
||||
}
|
||||
bool getUpsideDownArt() const
|
||||
{
|
||||
return upsideDownArt;
|
||||
}
|
||||
const QChar getColorChar() const;
|
||||
//@}
|
||||
|
||||
const QChar getColorChar() const;
|
||||
|
||||
/** @name Legacy/Convenience Property Accessors */ //@{
|
||||
const QString getCardType() const;
|
||||
void setCardType(const QString &value);
|
||||
|
|
|
|||
|
|
@ -282,9 +282,13 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
}
|
||||
|
||||
properties.insert("colors", colors);
|
||||
CardInfoPtr newCard =
|
||||
CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards, _sets, cipt,
|
||||
landscapeOrientation, tableRow, upsideDown);
|
||||
|
||||
CardInfo::UiAttributes attributes = {.cipt = cipt,
|
||||
.landscapeOrientation = landscapeOrientation,
|
||||
.tableRow = tableRow,
|
||||
.upsideDownArt = upsideDown};
|
||||
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
|
||||
reverseRelatedCards, _sets, attributes);
|
||||
emit addCard(newCard);
|
||||
}
|
||||
}
|
||||
|
|
@ -417,14 +421,15 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
|
|||
}
|
||||
|
||||
// positioning
|
||||
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
|
||||
if (info->getCipt()) {
|
||||
const CardInfo::UiAttributes &attributes = info->getUiAttributes();
|
||||
xml.writeTextElement("tablerow", QString::number(attributes.tableRow));
|
||||
if (attributes.cipt) {
|
||||
xml.writeTextElement("cipt", "1");
|
||||
}
|
||||
if (info->getLandscapeOrientation()) {
|
||||
if (attributes.landscapeOrientation) {
|
||||
xml.writeTextElement("landscapeOrientation", "1");
|
||||
}
|
||||
if (info->getUpsideDownArt()) {
|
||||
if (attributes.upsideDownArt) {
|
||||
xml.writeTextElement("upsidedown", "1");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,9 +262,12 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
continue;
|
||||
}
|
||||
|
||||
CardInfoPtr newCard =
|
||||
CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards, _sets, cipt,
|
||||
landscapeOrientation, tableRow, upsideDown);
|
||||
CardInfo::UiAttributes attributes = {.cipt = cipt,
|
||||
.landscapeOrientation = landscapeOrientation,
|
||||
.tableRow = tableRow,
|
||||
.upsideDownArt = upsideDown};
|
||||
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
|
||||
reverseRelatedCards, _sets, attributes);
|
||||
emit addCard(newCard);
|
||||
}
|
||||
}
|
||||
|
|
@ -379,14 +382,15 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
|
|||
}
|
||||
|
||||
// positioning
|
||||
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
|
||||
if (info->getCipt()) {
|
||||
const CardInfo::UiAttributes &attributes = info->getUiAttributes();
|
||||
xml.writeTextElement("tablerow", QString::number(attributes.tableRow));
|
||||
if (attributes.cipt) {
|
||||
xml.writeTextElement("cipt", "1");
|
||||
}
|
||||
if (info->getLandscapeOrientation()) {
|
||||
if (attributes.landscapeOrientation) {
|
||||
xml.writeTextElement("landscapeOrientation", "1");
|
||||
}
|
||||
if (info->getUpsideDownArt()) {
|
||||
if (attributes.upsideDownArt) {
|
||||
xml.writeTextElement("upsidedown", "1");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ void DeckList::refreshDeckHash()
|
|||
/**
|
||||
* Calls a given function on each card in the deck.
|
||||
*/
|
||||
void DeckList::forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func)
|
||||
void DeckList::forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func) const
|
||||
{
|
||||
// Support for this is only possible if the internal structure
|
||||
// doesn't get more complicated.
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ public:
|
|||
*
|
||||
* @param func Function taking (zone node, card node).
|
||||
*/
|
||||
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func);
|
||||
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ void GameFiltersSettings::setHideBuddiesOnlyGames(bool hide)
|
|||
bool GameFiltersSettings::isHideBuddiesOnlyGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_buddies_only_games");
|
||||
return previous == QVariant() || previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHideFullGames(bool hide)
|
||||
|
|
@ -36,7 +36,7 @@ void GameFiltersSettings::setHideFullGames(bool hide)
|
|||
bool GameFiltersSettings::isHideFullGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_full_games");
|
||||
return !(previous == QVariant()) && previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHideGamesThatStarted(bool hide)
|
||||
|
|
@ -47,7 +47,7 @@ void GameFiltersSettings::setHideGamesThatStarted(bool hide)
|
|||
bool GameFiltersSettings::isHideGamesThatStarted()
|
||||
{
|
||||
QVariant previous = getValue("hide_games_that_started");
|
||||
return !(previous == QVariant()) && previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHidePasswordProtectedGames(bool hide)
|
||||
|
|
@ -58,7 +58,7 @@ void GameFiltersSettings::setHidePasswordProtectedGames(bool hide)
|
|||
bool GameFiltersSettings::isHidePasswordProtectedGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_password_protected_games");
|
||||
return previous == QVariant() || previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHideIgnoredUserGames(bool hide)
|
||||
|
|
@ -69,7 +69,7 @@ void GameFiltersSettings::setHideIgnoredUserGames(bool hide)
|
|||
bool GameFiltersSettings::isHideIgnoredUserGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_ignored_user_games");
|
||||
return !(previous == QVariant()) && previous.toBool();
|
||||
return previous == QVariant() ? true : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide)
|
||||
|
|
@ -80,7 +80,7 @@ void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide)
|
|||
bool GameFiltersSettings::isHideNotBuddyCreatedGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_not_buddy_created_games");
|
||||
return !(previous == QVariant()) && previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
|
||||
|
|
@ -91,7 +91,7 @@ void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
|
|||
bool GameFiltersSettings::isHideOpenDecklistGames()
|
||||
{
|
||||
QVariant previous = getValue("hide_open_decklist_games");
|
||||
return !(previous == QVariant()) && previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setGameNameFilter(QString gameName)
|
||||
|
|
@ -104,14 +104,14 @@ QString GameFiltersSettings::getGameNameFilter()
|
|||
return getValue("game_name_filter").toString();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setCreatorNameFilter(QString creatorName)
|
||||
void GameFiltersSettings::setCreatorNameFilters(QStringList creatorName)
|
||||
{
|
||||
setValue(creatorName, "creator_name_filter");
|
||||
}
|
||||
|
||||
QString GameFiltersSettings::getCreatorNameFilter()
|
||||
QStringList GameFiltersSettings::getCreatorNameFilters()
|
||||
{
|
||||
return getValue("creator_name_filter").toString();
|
||||
return getValue("creator_name_filter").toStringList();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setMinPlayers(int min)
|
||||
|
|
@ -182,7 +182,7 @@ void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show)
|
|||
bool GameFiltersSettings::isShowSpectatorPasswordProtected()
|
||||
{
|
||||
QVariant previous = getValue("show_spectator_password_protected");
|
||||
return previous == QVariant() ? true : previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show)
|
||||
|
|
@ -193,7 +193,7 @@ void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show)
|
|||
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanChat()
|
||||
{
|
||||
QVariant previous = getValue("show_only_if_spectators_can_chat");
|
||||
return previous == QVariant() ? true : previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
||||
void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show)
|
||||
|
|
@ -204,5 +204,5 @@ void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show)
|
|||
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanSeeHands()
|
||||
{
|
||||
QVariant previous = getValue("show_only_if_spectators_can_see_hands");
|
||||
return previous == QVariant() ? true : previous.toBool();
|
||||
return previous == QVariant() ? false : previous.toBool();
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ public:
|
|||
bool isHideNotBuddyCreatedGames();
|
||||
bool isHideOpenDecklistGames();
|
||||
QString getGameNameFilter();
|
||||
QString getCreatorNameFilter();
|
||||
QStringList getCreatorNameFilters();
|
||||
int getMinPlayers();
|
||||
int getMaxPlayers();
|
||||
QTime getMaxGameAge();
|
||||
|
|
@ -42,7 +42,7 @@ public:
|
|||
void setHidePasswordProtectedGames(bool hide);
|
||||
void setHideNotBuddyCreatedGames(bool hide);
|
||||
void setGameNameFilter(QString gameName);
|
||||
void setCreatorNameFilter(QString creatorName);
|
||||
void setCreatorNameFilters(QStringList creatorName);
|
||||
void setMinPlayers(int min);
|
||||
void setMaxPlayers(int max);
|
||||
void setMaxGameAge(const QTime &maxGameAge);
|
||||
|
|
|
|||
|
|
@ -204,11 +204,11 @@ CardInfoPtr OracleImporter::addCard(QString name,
|
|||
bool upsideDown = layout == "flip" && side == "back";
|
||||
|
||||
// insert the card and its properties
|
||||
QList<CardRelation *> reverseRelatedCards;
|
||||
SetToPrintingsMap setsInfo;
|
||||
setsInfo[printingInfo.getSet()->getShortName()].append(printingInfo);
|
||||
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards,
|
||||
setsInfo, cipt, landscapeOrientation, tableRow, upsideDown);
|
||||
CardInfo::UiAttributes attributes = {cipt, landscapeOrientation, tableRow, upsideDown};
|
||||
CardInfoPtr newCard =
|
||||
CardInfo::newInstance(name, text, isToken, properties, relatedCards, {}, setsInfo, attributes);
|
||||
|
||||
if (name.isEmpty()) {
|
||||
qDebug() << "warning: an empty card was added to set" << printingInfo.getSet()->getShortName();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const serverPropsFile = `${ROOT_DIR}/server-props.json`;
|
|||
const masterProtoFile = `${ROOT_DIR}/proto-files.json`;
|
||||
|
||||
const sharedFiles = [
|
||||
['../common/pb', protoFilesDir],
|
||||
['../libcockatrice_protocol/libcockatrice/protocol/pb', protoFilesDir],
|
||||
['../cockatrice/resources/countries', `${ROOT_DIR}/images/countries`],
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue