mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-27 00:14:40 -07:00
Various fixes
Took 14 minutes
This commit is contained in:
parent
4779cc9742
commit
569b531113
15 changed files with 88 additions and 79 deletions
|
|
@ -101,7 +101,6 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||||
this, &DeckViewContainer::setVisualDeckStorageExists);
|
this, &DeckViewContainer::setVisualDeckStorageExists);
|
||||||
|
|
||||||
switchToDeckSelectView();
|
switchToDeckSelectView();
|
||||||
generateTutorialSequence();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TutorialSequence DeckViewContainer::generateTutorialSequence()
|
TutorialSequence DeckViewContainer::generateTutorialSequence()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#ifndef TABBED_DECK_VIEW_CONTAINER_H
|
#ifndef TABBED_DECK_VIEW_CONTAINER_H
|
||||||
#define TABBED_DECK_VIEW_CONTAINER_H
|
#define TABBED_DECK_VIEW_CONTAINER_H
|
||||||
|
#include "../../interface/widgets/general/tutorial/tutorial_controller.h"
|
||||||
#include "deck_view_container.h"
|
#include "deck_view_container.h"
|
||||||
|
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/network/client/remote/remote_client.h>
|
#include <libcockatrice/network/client/remote/remote_client.h>
|
||||||
#include <libcockatrice/settings/appearance_settings.h>
|
#include <libcockatrice/settings/appearance_settings.h>
|
||||||
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
#include <libcockatrice/settings/paths_settings.h>
|
#include <libcockatrice/settings/paths_settings.h>
|
||||||
#include <libcockatrice/utility/qt_utils.h>
|
|
||||||
|
|
||||||
HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
|
HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
|
||||||
: QWidget(parent), tabSupervisor(_tabSupervisor), background("theme:backgrounds/home"), overlay("theme:cockatrice")
|
: QWidget(parent), tabSupervisor(_tabSupervisor), background("theme:backgrounds/home"), overlay("theme:cockatrice")
|
||||||
|
|
@ -50,13 +50,7 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
|
||||||
connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabBackgroundShuffleFrequencyChanged,
|
connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabBackgroundShuffleFrequencyChanged,
|
||||||
this, &HomeWidget::onBackgroundShuffleFrequencyChanged);
|
this, &HomeWidget::onBackgroundShuffleFrequencyChanged);
|
||||||
|
|
||||||
auto mainWindow = QtUtils::findParentOfType<QMainWindow>(this);
|
tutorialController = new TutorialController(this);
|
||||||
|
|
||||||
if (mainWindow) {
|
|
||||||
tutorialController = new TutorialController(mainWindow);
|
|
||||||
} else {
|
|
||||||
tutorialController = new TutorialController(this);
|
|
||||||
}
|
|
||||||
auto sequence = TutorialSequence();
|
auto sequence = TutorialSequence();
|
||||||
sequence.addStep({connectButton, "Connect to a server to play here!"});
|
sequence.addStep({connectButton, "Connect to a server to play here!"});
|
||||||
auto vdeStep = TutorialStep{visualDeckEditorButton, "Create a new deck from cards in the database here!"};
|
auto vdeStep = TutorialStep{visualDeckEditorButton, "Create a new deck from cards in the database here!"};
|
||||||
|
|
@ -92,7 +86,7 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
|
||||||
void HomeWidget::showEvent(QShowEvent *event)
|
void HomeWidget::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::showEvent(event);
|
QWidget::showEvent(event);
|
||||||
if (!tutorialStarted) {
|
if (!tutorialStarted && !SettingsCache::instance().userInterface().getTutorialCompleted()) {
|
||||||
tutorialStarted = true;
|
tutorialStarted = true;
|
||||||
// Start on next event loop iteration so everything is fully painted
|
// Start on next event loop iteration so everything is fully painted
|
||||||
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||||
|
|
||||||
|
class TutorialController;
|
||||||
|
|
||||||
class HomeWidget : public QWidget
|
class HomeWidget : public QWidget
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#include "tutorial_controller.h"
|
#include "tutorial_controller.h"
|
||||||
|
|
||||||
|
#include "../../../../client/settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDebug>
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
|
|
||||||
TutorialController::TutorialController(QWidget *_tutorializedWidget)
|
TutorialController::TutorialController(QWidget *_tutorializedWidget)
|
||||||
: QObject(_tutorializedWidget), tutorializedWidget(_tutorializedWidget)
|
: QObject(_tutorializedWidget), tutorializedWidget(_tutorializedWidget)
|
||||||
|
|
@ -24,6 +26,18 @@ TutorialController::TutorialController(QWidget *_tutorializedWidget)
|
||||||
connect(tutorialOverlay, &TutorialOverlay::targetClicked, this, &TutorialController::handleTargetClicked);
|
connect(tutorialOverlay, &TutorialOverlay::targetClicked, this, &TutorialController::handleTargetClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TutorialController::~TutorialController()
|
||||||
|
{
|
||||||
|
// The overlay is parented to the top-level window, which outlives the widget
|
||||||
|
// this controller is attached to (e.g. a closed tab), so it must be cleaned
|
||||||
|
// up explicitly when the controller goes away without exitTutorial().
|
||||||
|
if (tutorialOverlay) {
|
||||||
|
tutorialOverlay->hide();
|
||||||
|
tutorialOverlay->deleteLater();
|
||||||
|
}
|
||||||
|
tutorialOverlay = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void TutorialController::addSequence(const TutorialSequence &seq)
|
void TutorialController::addSequence(const TutorialSequence &seq)
|
||||||
{
|
{
|
||||||
sequences.append(seq);
|
sequences.append(seq);
|
||||||
|
|
@ -172,12 +186,15 @@ void TutorialController::prevSequence()
|
||||||
void TutorialController::exitTutorial()
|
void TutorialController::exitTutorial()
|
||||||
{
|
{
|
||||||
cleanupValidationMonitoring();
|
cleanupValidationMonitoring();
|
||||||
tutorialOverlay->hide();
|
if (tutorialOverlay) {
|
||||||
// TODO Maybe not the best idea:
|
tutorialOverlay->hide();
|
||||||
tutorialOverlay->deleteLater();
|
tutorialOverlay->deleteLater();
|
||||||
|
}
|
||||||
|
tutorialOverlay = nullptr;
|
||||||
currentSequence = -1;
|
currentSequence = -1;
|
||||||
currentStep = -1;
|
currentStep = -1;
|
||||||
tutorialCompleted = true;
|
tutorialCompleted = true;
|
||||||
|
SettingsCache::instance().userInterface().setTutorialCompleted(true);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,6 +254,7 @@ void TutorialController::showStep()
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupValidationMonitoring();
|
cleanupValidationMonitoring();
|
||||||
|
advanceScheduled = false;
|
||||||
|
|
||||||
const auto &step = seq.steps[currentStep];
|
const auto &step = seq.steps[currentStep];
|
||||||
|
|
||||||
|
|
@ -278,13 +296,7 @@ void TutorialController::setupValidationMonitoring()
|
||||||
// Handle OnSignal validation - connect to any custom signal
|
// Handle OnSignal validation - connect to any custom signal
|
||||||
if (step.validationTiming == ValidationTiming::OnSignal && step.validator) {
|
if (step.validationTiming == ValidationTiming::OnSignal && step.validator) {
|
||||||
if (step.signalSource && step.signalName) {
|
if (step.signalSource && step.signalName) {
|
||||||
qInfo() << "Setting up signal-based validation for signal:" << step.signalName;
|
|
||||||
validationConnection = connect(step.signalSource, step.signalName, this, SLOT(checkValidation()));
|
validationConnection = connect(step.signalSource, step.signalName, this, SLOT(checkValidation()));
|
||||||
if (!validationConnection) {
|
|
||||||
qInfo() << "Warning: Failed to connect to signal" << step.signalName;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qInfo() << "Warning: OnSignal validation timing set but signalSource or signalName is null";
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -292,24 +304,17 @@ void TutorialController::setupValidationMonitoring()
|
||||||
// Handle OnChange validation - widget-specific
|
// Handle OnChange validation - widget-specific
|
||||||
if (step.validationTiming == ValidationTiming::OnChange && step.validator) {
|
if (step.validationTiming == ValidationTiming::OnChange && step.validator) {
|
||||||
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(step.targetWidget)) {
|
if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(step.targetWidget)) {
|
||||||
qInfo() << "Setting up validation monitoring for QLineEdit";
|
|
||||||
validationConnection =
|
validationConnection =
|
||||||
connect(lineEdit, &QLineEdit::textChanged, this, &TutorialController::checkValidation);
|
connect(lineEdit, &QLineEdit::textChanged, this, &TutorialController::checkValidation);
|
||||||
} else if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(step.targetWidget)) {
|
} else if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(step.targetWidget)) {
|
||||||
qInfo() << "Setting up validation monitoring for QTextEdit";
|
|
||||||
validationConnection =
|
validationConnection =
|
||||||
connect(textEdit, &QTextEdit::textChanged, this, &TutorialController::checkValidation);
|
connect(textEdit, &QTextEdit::textChanged, this, &TutorialController::checkValidation);
|
||||||
} else if (QPlainTextEdit *plainText = qobject_cast<QPlainTextEdit *>(step.targetWidget)) {
|
} else if (QPlainTextEdit *plainText = qobject_cast<QPlainTextEdit *>(step.targetWidget)) {
|
||||||
qInfo() << "Setting up validation monitoring for QPlainTextEdit";
|
|
||||||
validationConnection =
|
validationConnection =
|
||||||
connect(plainText, &QPlainTextEdit::textChanged, this, &TutorialController::checkValidation);
|
connect(plainText, &QPlainTextEdit::textChanged, this, &TutorialController::checkValidation);
|
||||||
} else if (QComboBox *combo = qobject_cast<QComboBox *>(step.targetWidget)) {
|
} else if (QComboBox *combo = qobject_cast<QComboBox *>(step.targetWidget)) {
|
||||||
qInfo() << "Setting up validation monitoring for QComboBox";
|
|
||||||
validationConnection = connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
validationConnection = connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&TutorialController::checkValidation);
|
&TutorialController::checkValidation);
|
||||||
} else {
|
|
||||||
qInfo() << "Warning: OnChange validation timing set but widget type not supported:"
|
|
||||||
<< (step.targetWidget ? step.targetWidget->metaObject()->className() : "null");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -317,7 +322,6 @@ void TutorialController::setupValidationMonitoring()
|
||||||
void TutorialController::cleanupValidationMonitoring()
|
void TutorialController::cleanupValidationMonitoring()
|
||||||
{
|
{
|
||||||
if (validationConnection) {
|
if (validationConnection) {
|
||||||
qInfo() << "Cleaning up validation connection";
|
|
||||||
disconnect(validationConnection);
|
disconnect(validationConnection);
|
||||||
validationConnection = QMetaObject::Connection();
|
validationConnection = QMetaObject::Connection();
|
||||||
}
|
}
|
||||||
|
|
@ -325,8 +329,6 @@ void TutorialController::cleanupValidationMonitoring()
|
||||||
|
|
||||||
void TutorialController::checkValidation()
|
void TutorialController::checkValidation()
|
||||||
{
|
{
|
||||||
qInfo() << "checkValidation() called";
|
|
||||||
|
|
||||||
if (currentSequence < 0 || currentSequence >= sequences.size()) {
|
if (currentSequence < 0 || currentSequence >= sequences.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -338,16 +340,18 @@ void TutorialController::checkValidation()
|
||||||
|
|
||||||
if (step.validator) {
|
if (step.validator) {
|
||||||
bool isValid = step.validator();
|
bool isValid = step.validator();
|
||||||
qInfo() << "Validation result:" << isValid;
|
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
// Clear any validation hints
|
// Clear any validation hints
|
||||||
tutorialOverlay->showValidationHint("");
|
tutorialOverlay->showValidationHint("");
|
||||||
|
|
||||||
// Auto-advance if enabled
|
// Auto-advance if enabled
|
||||||
if (step.autoAdvanceOnValid) {
|
if (step.autoAdvanceOnValid && !advanceScheduled) {
|
||||||
qInfo() << "Auto-advancing to next step";
|
advanceScheduled = true;
|
||||||
QTimer::singleShot(500, this, &TutorialController::nextStep);
|
QTimer::singleShot(500, this, [this]() {
|
||||||
|
advanceScheduled = false;
|
||||||
|
nextStep();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ class TutorialController : public QObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TutorialController(QWidget *_tutorializedWidget);
|
explicit TutorialController(QWidget *_tutorializedWidget);
|
||||||
|
~TutorialController() override;
|
||||||
|
|
||||||
void addSequence(const TutorialSequence &seq);
|
void addSequence(const TutorialSequence &seq);
|
||||||
void start();
|
void start();
|
||||||
|
|
@ -95,6 +96,10 @@ private:
|
||||||
|
|
||||||
// For OnChange validation monitoring
|
// For OnChange validation monitoring
|
||||||
QMetaObject::Connection validationConnection;
|
QMetaObject::Connection validationConnection;
|
||||||
|
|
||||||
|
// True while an auto-advance timer is pending, so repeated signal emissions
|
||||||
|
// can't queue more than one advance.
|
||||||
|
bool advanceScheduled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_TUTORIAL_CONTROLLER_H
|
#endif // COCKATRICE_TUTORIAL_CONTROLLER_H
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,9 @@ void TutorialOverlay::recomputeLayout()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resize(parentWidget()->window()->geometry().size());
|
// The overlay is parented to the top-level window; its client size (rect())
|
||||||
|
// is the visible area, whereas window()->geometry() includes the frame.
|
||||||
|
resize(parentWidget()->size());
|
||||||
|
|
||||||
bubble->adjustSize();
|
bubble->adjustSize();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
#include "../interface/window_main.h"
|
#include "../interface/window_main.h"
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
#include "../utility/visibility_change_listener.h"
|
#include "../utility/visibility_change_listener.h"
|
||||||
#include "libcockatrice/utility/qt_utils.h"
|
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
|
@ -140,13 +139,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
||||||
|
|
||||||
QTimer::singleShot(0, this, &TabGame::loadLayout);
|
QTimer::singleShot(0, this, &TabGame::loadLayout);
|
||||||
|
|
||||||
auto mainWindow = QtUtils::findParentOfType<QMainWindow>(this);
|
tutorialController = new TutorialController(this);
|
||||||
|
|
||||||
if (mainWindow) {
|
|
||||||
tutorialController = new TutorialController(mainWindow);
|
|
||||||
} else {
|
|
||||||
tutorialController = new TutorialController(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
TutorialSequence lobbySequence;
|
TutorialSequence lobbySequence;
|
||||||
|
|
||||||
|
|
@ -159,7 +152,12 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
||||||
void TabGame::showEvent(QShowEvent *event)
|
void TabGame::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::showEvent(event);
|
QWidget::showEvent(event);
|
||||||
if (!tutorialStarted) {
|
if (!tutorialController || tutorialStarted || SettingsCache::instance().userInterface().getTutorialCompleted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Only start once all sequences are registered so advancing can't run past the
|
||||||
|
// end of an incomplete sequence list.
|
||||||
|
if (tutorialInitialized) {
|
||||||
tutorialStarted = true;
|
tutorialStarted = true;
|
||||||
// Start on next event loop iteration so everything is fully painted
|
// Start on next event loop iteration so everything is fully painted
|
||||||
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
||||||
|
|
@ -189,7 +187,7 @@ void TabGame::finishTutorialInitialization()
|
||||||
loadDeckStep.autoAdvanceOnValid = true;
|
loadDeckStep.autoAdvanceOnValid = true;
|
||||||
loadDeckStep.validationTiming = ValidationTiming::OnSignal;
|
loadDeckStep.validationTiming = ValidationTiming::OnSignal;
|
||||||
loadDeckStep.signalSource = game->getGameEventHandler();
|
loadDeckStep.signalSource = game->getGameEventHandler();
|
||||||
loadDeckStep.signalName = SIGNAL(logDeckSelect(Player *, QString, int));
|
loadDeckStep.signalName = SIGNAL(logDeckSelect(PlayerLogic *, QString, int));
|
||||||
loadDeckStep.validator = [] { return true; };
|
loadDeckStep.validator = [] { return true; };
|
||||||
|
|
||||||
deckSelectSequence.addStep(loadDeckStep);
|
deckSelectSequence.addStep(loadDeckStep);
|
||||||
|
|
@ -215,9 +213,6 @@ void TabGame::finishTutorialInitialization()
|
||||||
gamePlaySequence.addStep(
|
gamePlaySequence.addStep(
|
||||||
{gamePlayAreaWidget,
|
{gamePlayAreaWidget,
|
||||||
tr("Welcome to your first game! It's just a singleplayer game for now to teach you the controls.")});
|
tr("Welcome to your first game! It's just a singleplayer game for now to teach you the controls.")});
|
||||||
gamePlaySequence.addStep(
|
|
||||||
{gamePlayAreaWidget,
|
|
||||||
tr("Welcome to your first game! It's just a singleplayer game for now to teach you the controls.")});
|
|
||||||
gamePlaySequence.addStep(
|
gamePlaySequence.addStep(
|
||||||
{gamePlayAreaWidget,
|
{gamePlayAreaWidget,
|
||||||
tr("Unfortunately, due to the way the game tab works, we can't highlight any specific gameplay elements but "
|
tr("Unfortunately, due to the way the game tab works, we can't highlight any specific gameplay elements but "
|
||||||
|
|
@ -264,7 +259,7 @@ void TabGame::finishTutorialInitialization()
|
||||||
lifeCounterStep.signalSource = game->getPlayerManager()
|
lifeCounterStep.signalSource = game->getPlayerManager()
|
||||||
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
||||||
->getPlayerEventHandler();
|
->getPlayerEventHandler();
|
||||||
lifeCounterStep.signalName = SIGNAL(logSetCounter(Player *, QString, int, int));
|
lifeCounterStep.signalName = SIGNAL(logSetCounter(PlayerLogic *, QString, int, int));
|
||||||
lifeCounterStep.validator = [this] {
|
lifeCounterStep.validator = [this] {
|
||||||
auto counters =
|
auto counters =
|
||||||
game->getPlayerManager()->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())->getCounters();
|
game->getPlayerManager()->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())->getCounters();
|
||||||
|
|
@ -291,7 +286,7 @@ void TabGame::finishTutorialInitialization()
|
||||||
diceRollStep.signalSource = game->getPlayerManager()
|
diceRollStep.signalSource = game->getPlayerManager()
|
||||||
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
||||||
->getPlayerEventHandler();
|
->getPlayerEventHandler();
|
||||||
diceRollStep.signalName = SIGNAL(logRollDie(Player *, int, const QList<uint> &));
|
diceRollStep.signalName = SIGNAL(logRollDie(PlayerLogic *, int, const QList<uint> &));
|
||||||
diceRollStep.validator = [] { return true; };
|
diceRollStep.validator = [] { return true; };
|
||||||
diceRollStep.validationHint = tr("Roll a dice using any of these methods.");
|
diceRollStep.validationHint = tr("Roll a dice using any of these methods.");
|
||||||
|
|
||||||
|
|
@ -310,7 +305,7 @@ void TabGame::finishTutorialInitialization()
|
||||||
mulliganStep.signalSource = game->getPlayerManager()
|
mulliganStep.signalSource = game->getPlayerManager()
|
||||||
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
||||||
->getPlayerEventHandler();
|
->getPlayerEventHandler();
|
||||||
mulliganStep.signalName = SIGNAL(logDrawCards(Player *, int, bool));
|
mulliganStep.signalName = SIGNAL(logDrawCards(PlayerLogic *, int, bool));
|
||||||
mulliganStep.validator = [this] {
|
mulliganStep.validator = [this] {
|
||||||
return game->getPlayerManager()
|
return game->getPlayerManager()
|
||||||
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
->getActiveLocalPlayer(game->getPlayerManager()->getLocalPlayerId())
|
||||||
|
|
@ -322,11 +317,17 @@ void TabGame::finishTutorialInitialization()
|
||||||
|
|
||||||
gamePlaySequence.addStep(mulliganStep);
|
gamePlaySequence.addStep(mulliganStep);
|
||||||
|
|
||||||
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
||||||
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
||||||
|
|
||||||
gamePlaySequence.addStep({gamePlayAreaWidget, tr("")});
|
|
||||||
tutorialController->addSequence(gamePlaySequence);
|
tutorialController->addSequence(gamePlaySequence);
|
||||||
|
|
||||||
|
if (tutorialStarted || SettingsCache::instance().userInterface().getTutorialCompleted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// The tab may have been shown before the local player joined; start now that
|
||||||
|
// the full sequence list is registered.
|
||||||
|
if (isVisible()) {
|
||||||
|
tutorialStarted = true;
|
||||||
|
QTimer::singleShot(3, tutorialController, [this] { tutorialController->start(); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabGame::connectToGameState()
|
void TabGame::connectToGameState()
|
||||||
|
|
@ -953,8 +954,6 @@ void TabGame::loadDeckForLocalPlayer(PlayerLogic *localPlayer, int playerId, Ser
|
||||||
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(deckList.getCardRefList()));
|
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(deckList.getCardRefList()));
|
||||||
deckViewContainer->playerDeckView->setDeck(deckList);
|
deckViewContainer->playerDeckView->setDeck(deckList);
|
||||||
localPlayer->setDeck(deckList);
|
localPlayer->setDeck(deckList);
|
||||||
|
|
||||||
emit localPlayerDeckSelected();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game");
|
||||||
class UserListProxy;
|
class UserListProxy;
|
||||||
class DeckViewContainer;
|
class DeckViewContainer;
|
||||||
class AbstractClient;
|
class AbstractClient;
|
||||||
|
class TutorialController;
|
||||||
class CardDatabase;
|
class CardDatabase;
|
||||||
class GameView;
|
class GameView;
|
||||||
class GameScene;
|
class GameScene;
|
||||||
|
|
@ -58,7 +59,7 @@ class TabGame : public Tab
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
AbstractGame *game;
|
AbstractGame *game;
|
||||||
TutorialController *tutorialController;
|
TutorialController *tutorialController = nullptr;
|
||||||
bool tutorialStarted = false;
|
bool tutorialStarted = false;
|
||||||
bool tutorialInitialized = false;
|
bool tutorialInitialized = false;
|
||||||
const UserListProxy *userListProxy;
|
const UserListProxy *userListProxy;
|
||||||
|
|
@ -130,7 +131,6 @@ private:
|
||||||
void createDeckViewContainerWidget(bool bReplay = false);
|
void createDeckViewContainerWidget(bool bReplay = false);
|
||||||
void createReplayDock(GameReplay *replay);
|
void createReplayDock(GameReplay *replay);
|
||||||
signals:
|
signals:
|
||||||
void localPlayerDeckSelected();
|
|
||||||
void localPlayerReadyStateChanged(bool ready);
|
void localPlayerReadyStateChanged(bool ready);
|
||||||
void gameClosing(TabGame *tab);
|
void gameClosing(TabGame *tab);
|
||||||
void containerProcessingStarted(const GameEventContext &context);
|
void containerProcessingStarted(const GameEventContext &context);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||||
#include <libcockatrice/protocol/pb/command_deck_upload.pb.h>
|
#include <libcockatrice/protocol/pb/command_deck_upload.pb.h>
|
||||||
#include <libcockatrice/protocol/pending_command.h>
|
#include <libcockatrice/protocol/pending_command.h>
|
||||||
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
#include <libcockatrice/settings/layouts_settings.h>
|
#include <libcockatrice/settings/layouts_settings.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,8 +75,6 @@ TabDeckEditorVisual::TabDeckEditorVisual(TabSupervisor *_tabSupervisor) : Abstra
|
||||||
"adding some now, so you can see it in action!",
|
"adding some now, so you can see it in action!",
|
||||||
[this]() { tabContainer->setCurrentWidget(tabContainer->visualDeckView); }});
|
[this]() { tabContainer->setCurrentWidget(tabContainer->visualDeckView); }});
|
||||||
|
|
||||||
// sequence.addStep({printingSelectorDockWidget, "Change the printings in your deck here."});
|
|
||||||
|
|
||||||
tutorialController->addSequence(sequence);
|
tutorialController->addSequence(sequence);
|
||||||
|
|
||||||
auto vdeSequence = tabContainer->visualDeckView->addTutorialSteps();
|
auto vdeSequence = tabContainer->visualDeckView->addTutorialSteps();
|
||||||
|
|
@ -130,7 +129,7 @@ TabDeckEditorVisual::TabDeckEditorVisual(TabSupervisor *_tabSupervisor) : Abstra
|
||||||
void TabDeckEditorVisual::showEvent(QShowEvent *ev)
|
void TabDeckEditorVisual::showEvent(QShowEvent *ev)
|
||||||
{
|
{
|
||||||
QWidget::showEvent(ev);
|
QWidget::showEvent(ev);
|
||||||
if (!tutorialStarted) {
|
if (!tutorialStarted && !SettingsCache::instance().userInterface().getTutorialCompleted()) {
|
||||||
tutorialStarted = true;
|
tutorialStarted = true;
|
||||||
// Start on next event loop iteration so everything is fully painted
|
// Start on next event loop iteration so everything is fully painted
|
||||||
QTimer::singleShot(0, tutorialController, [this] { tutorialController->start(); });
|
QTimer::singleShot(0, tutorialController, [this] { tutorialController->start(); });
|
||||||
|
|
|
||||||
|
|
@ -163,15 +163,19 @@ TutorialSequence VisualDatabaseDisplayWidget::addTutorialSteps()
|
||||||
|
|
||||||
TutorialStep explorationStep;
|
TutorialStep explorationStep;
|
||||||
explorationStep.targetWidget = this;
|
explorationStep.targetWidget = this;
|
||||||
explorationStep.text = tr(
|
explorationStep.text = tr("Try it out!\n\nAdd 5 different new cards to the deck by clicking on them!");
|
||||||
"Try it out!\n\nWe've cleared the previous deck. Add 5 different new cards to the deck by clicking on them!");
|
|
||||||
explorationStep.allowClickThrough = true;
|
explorationStep.allowClickThrough = true;
|
||||||
explorationStep.requiresInteraction = true;
|
explorationStep.requiresInteraction = true;
|
||||||
explorationStep.autoAdvanceOnValid = true;
|
explorationStep.autoAdvanceOnValid = true;
|
||||||
explorationStep.validationTiming = ValidationTiming::OnSignal;
|
explorationStep.validationTiming = ValidationTiming::OnSignal;
|
||||||
if (QtUtils::findParentOfType<TabDeckEditorVisual>(this)) {
|
if (QtUtils::findParentOfType<TabDeckEditorVisual>(this)) {
|
||||||
explorationStep.onEnter = [this] {
|
explorationStep.onEnter = [this] {
|
||||||
QtUtils::findParentOfType<TabDeckEditorVisual>(this)->deckStateManager->clearDeck();
|
auto deckEditor = QtUtils::findParentOfType<TabDeckEditorVisual>(this);
|
||||||
|
// Only clear an empty starter deck; never destroy a deck the user may
|
||||||
|
// have opened with existing cards.
|
||||||
|
if (deckEditor->deckStateManager->getModel()->getDeckList()->getCardList().isEmpty()) {
|
||||||
|
deckEditor->deckStateManager->clearDeck();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
explorationStep.signalSource =
|
explorationStep.signalSource =
|
||||||
QtUtils::findParentOfType<TabDeckEditorVisual>(this)->deckStateManager->getModel();
|
QtUtils::findParentOfType<TabDeckEditorVisual>(this)->deckStateManager->getModel();
|
||||||
|
|
@ -203,19 +207,6 @@ TutorialSequence VisualDatabaseDisplayWidget::addTutorialSteps()
|
||||||
|
|
||||||
sequence.addStep(conclusionStep);
|
sequence.addStep(conclusionStep);
|
||||||
|
|
||||||
/*sequence.addStep(
|
|
||||||
{quickFilterSaveLoadWidget, "This button will let you save and load all currently applied filters to files."});
|
|
||||||
sequence.addStep({quickFilterNameWidget,
|
|
||||||
"This button will let you apply name filters. Optionally, you can import every card in "
|
|
||||||
"your deck as a name filter and then save this as a filter using the save/load button "
|
|
||||||
"to make your own quick access collections!"});
|
|
||||||
sequence.addStep({mainTypeFilterWidget, "Use these buttons to quickly filter by card types."});
|
|
||||||
sequence.addStep({quickFilterSubTypeWidget, "This button will let you apply filters for card sub-types."});
|
|
||||||
sequence.addStep(
|
|
||||||
{quickFilterSetWidget,
|
|
||||||
"This button will let you apply filters for card sets. You can also filter to the X most recent sets. "
|
|
||||||
"Filtering to a set will display all printings of a card within that set."});*/
|
|
||||||
|
|
||||||
return sequence;
|
return sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H
|
#ifndef COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H
|
||||||
#define COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H
|
#define COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H
|
||||||
|
|
||||||
|
#include "../general/tutorial/tutorial_controller.h"
|
||||||
#include "visual_deck_editor_widget.h"
|
#include "visual_deck_editor_widget.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
|
|
||||||
|
|
@ -479,7 +479,7 @@ TutorialSequence VisualDeckEditorWidget::addTutorialSteps()
|
||||||
searchStep.allowClickThrough = true;
|
searchStep.allowClickThrough = true;
|
||||||
searchStep.requiresInteraction = true;
|
searchStep.requiresInteraction = true;
|
||||||
searchStep.autoAdvanceOnValid = true;
|
searchStep.autoAdvanceOnValid = true;
|
||||||
searchStep.validationTiming = ValidationTiming::OnChange; // Make sure this is set!
|
searchStep.validationTiming = ValidationTiming::OnChange;
|
||||||
searchStep.validator = [this]() {
|
searchStep.validator = [this]() {
|
||||||
return CardDatabaseManager::query()->getCard({searchBar->text()}) != ExactCard();
|
return CardDatabaseManager::query()->getCard({searchBar->text()}) != ExactCard();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,11 @@ bool InterfaceSettings::getShowGameSelectorFilterToolbar() const
|
||||||
return getValue("showGameSelectorFilterToolbar", QString(), QString(), true).toBool();
|
return getValue("showGameSelectorFilterToolbar", QString(), QString(), true).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InterfaceSettings::getTutorialCompleted() const
|
||||||
|
{
|
||||||
|
return getValue("tutorialCompleted", QString(), QString(), false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
void InterfaceSettings::setUseTearOffMenus(bool _useTearOffMenus)
|
void InterfaceSettings::setUseTearOffMenus(bool _useTearOffMenus)
|
||||||
{
|
{
|
||||||
setValue(_useTearOffMenus, "useTearOffMenus");
|
setValue(_useTearOffMenus, "useTearOffMenus");
|
||||||
|
|
@ -316,3 +321,8 @@ void InterfaceSettings::setShowGameSelectorFilterToolbar(bool _showGameSelectorF
|
||||||
setValue(_showGameSelectorFilterToolbar, "showGameSelectorFilterToolbar");
|
setValue(_showGameSelectorFilterToolbar, "showGameSelectorFilterToolbar");
|
||||||
emit showGameSelectorFilterToolbarChanged(_showGameSelectorFilterToolbar);
|
emit showGameSelectorFilterToolbarChanged(_showGameSelectorFilterToolbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InterfaceSettings::setTutorialCompleted(bool value)
|
||||||
|
{
|
||||||
|
setValue(value, "tutorialCompleted");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ public:
|
||||||
[[nodiscard]] bool getShowStatusBar() const override;
|
[[nodiscard]] bool getShowStatusBar() const override;
|
||||||
[[nodiscard]] bool getShowShortcuts() const override;
|
[[nodiscard]] bool getShowShortcuts() const override;
|
||||||
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const override;
|
[[nodiscard]] bool getShowGameSelectorFilterToolbar() const override;
|
||||||
|
[[nodiscard]] bool getTutorialCompleted() const;
|
||||||
|
|
||||||
void setUseTearOffMenus(bool _useTearOffMenus);
|
void setUseTearOffMenus(bool _useTearOffMenus);
|
||||||
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
void setCardViewInitialRowsMax(int _cardViewInitialRowsMax);
|
||||||
|
|
@ -72,6 +73,7 @@ public:
|
||||||
void setShowStatusBar(bool _showStatusBar);
|
void setShowStatusBar(bool _showStatusBar);
|
||||||
void setShowShortcuts(bool _showShortcuts);
|
void setShowShortcuts(bool _showShortcuts);
|
||||||
void setShowGameSelectorFilterToolbar(bool _showGameSelectorFilterToolbar);
|
void setShowGameSelectorFilterToolbar(bool _showGameSelectorFilterToolbar);
|
||||||
|
void setTutorialCompleted(bool value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void useTearOffMenusChanged(bool state);
|
void useTearOffMenusChanged(bool state);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue