[VDE] Add a new setting to determine initial tab (Context/Deck/Database) (#7122)

* [VDE] Add a new setting to determine initial tab (Context/Deck/Database)

Took 16 minutes

Took 4 seconds

* Adjust tooltip

Took 4 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-15 21:55:39 +02:00 committed by GitHub
parent 6ee1fd58e6
commit fbe5c4ade0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 108 additions and 5 deletions

View file

@ -183,6 +183,13 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
connect(&defaultDeckEditorTypeSelector, QOverload<int>::of(&QComboBox::currentIndexChanged),
&SettingsCache::instance().deckEditor(), &DeckEditorSettings::setDefaultDeckEditorType);
vdeStartupTabSelector.addItem(""); // these will be set in retranslateUI
vdeStartupTabSelector.addItem("");
vdeStartupTabSelector.addItem("");
vdeStartupTabSelector.setCurrentIndex(SettingsCache::instance().deckEditor().getVdeStartupTab());
connect(&vdeStartupTabSelector, QOverload<int>::of(&QComboBox::currentIndexChanged),
&SettingsCache::instance().deckEditor(), &DeckEditorSettings::setVdeStartupTab);
commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setText("?");
commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setAutoRaise(true);
commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setEnabled(false);
@ -242,10 +249,12 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1);
deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0);
deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledLabel, 5, 0);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledSelector, 5, 1);
deckEditorGrid->addWidget(labelWidget, 6, 0);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationBracketNamingSelector, 6, 1);
deckEditorGrid->addWidget(&vdeStartupTabLabel, 5, 0);
deckEditorGrid->addWidget(&vdeStartupTabSelector, 5, 1);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledLabel, 6, 0);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledSelector, 6, 1);
deckEditorGrid->addWidget(labelWidget, 7, 0);
deckEditorGrid->addWidget(&commanderSpellbookIntegrationBracketNamingSelector, 7, 1);
deckEditorGroupBox = new QGroupBox;
deckEditorGroupBox->setLayout(deckEditorGrid);
@ -368,6 +377,12 @@ void UserInterfaceSettingsPage::retranslateUi()
defaultDeckEditorTypeLabel.setText(tr("Default deck editor type"));
defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor"));
defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor"));
vdeStartupTabLabel.setText(tr("Visual deck editor startup tab"));
vdeStartupTabSelector.setItemText(VdeStartupTabContext, tr("Context"));
vdeStartupTabSelector.setItemText(VdeStartupTabDeckDisplay, tr("Deck display"));
vdeStartupTabSelector.setItemText(VdeStartupTabDatabaseDisplay, tr("Database display"));
vdeStartupTabSelector.setToolTip(
tr("Context mode: New decks open on the database display, existing decks open on the deck view."));
commanderSpellbookIntegrationEnabledLabel.setText(
tr("CommanderSpellbook integration to estimate commander bracket"));

View file

@ -50,6 +50,8 @@ private:
QCheckBox visualDeckStorageSelectionAnimationCheckBox;
QLabel defaultDeckEditorTypeLabel;
QComboBox defaultDeckEditorTypeSelector;
QLabel vdeStartupTabLabel;
QComboBox vdeStartupTabSelector;
QLabel commanderSpellbookIntegrationEnabledLabel;
QComboBox commanderSpellbookIntegrationEnabledSelector;
QLabel commanderSpellbookIntegrationUseOfficialBracketNamesLabel;

View file

@ -263,12 +263,12 @@ protected slots:
/** @brief Handles dock close events. */
void closeEvent(QCloseEvent *event) override;
private:
/** @brief Sets the deck for this tab.
* @param _deck The deck object.
*/
virtual void setDeck(const LoadedDeck &_deck);
private:
/** @brief Helper for editing decks from the clipboard. */
void editDeckInClipboard(bool annotated);

View file

@ -30,6 +30,7 @@
#include <libcockatrice/models/deck_list/deck_list_model.h>
#include <libcockatrice/protocol/pb/command_deck_upload.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/settings/deck_editor_settings.h>
#include <libcockatrice/settings/layouts_settings.h>
/**
@ -98,6 +99,33 @@ void TabDeckEditorVisual::onDeckChanged()
tabContainer->sampleHandWidget->setDeckModel(deckStateManager->getModel());
}
/** @brief Sets the deck and selects the startup sub-tab matching the context. */
void TabDeckEditorVisual::setDeck(const LoadedDeck &_deck)
{
AbstractTabDeckEditor::setDeck(_deck);
int startupTab = SettingsCache::instance().deckEditor().getVdeStartupTab();
if (startupTab == VdeStartupTabContext) {
// New (empty) decks open on the database display so cards can be added
// right away. Existing decks open on the deck view.
startupTab = _deck.isEmpty() ? VdeStartupTabDatabaseDisplay : VdeStartupTabDeckDisplay;
}
switch (startupTab) {
case VdeStartupTabDatabaseDisplay:
tabContainer->setCurrentIndex(TabDeckEditorVisualTabWidget::TabIndex::VisualDatabaseDisplay);
break;
case VdeStartupTabDeckDisplay:
tabContainer->setCurrentIndex(TabDeckEditorVisualTabWidget::TabIndex::VisualDeckView);
break;
default:
qCWarning(TabSupervisorLog) << "Unknown VdeStartupTab [" << startupTab
<< "]; falling back to the deck view";
tabContainer->setCurrentIndex(TabDeckEditorVisualTabWidget::TabIndex::VisualDeckView);
break;
}
}
/** @brief Creates menus for deck editing and view options, including dock actions. */
void TabDeckEditorVisual::createMenus()
{

View file

@ -164,6 +164,15 @@ public slots:
* @return true if successful, false otherwise.
*/
bool actSaveDeckAs() override;
private:
/**
* @brief Sets the deck for this tab and selects the sub-tab to open on
* startup, per the "Visual deck editor startup tab" setting (Context /
* Deck display / Database display).
* @param _deck The deck object.
*/
void setDeck(const LoadedDeck &_deck) override;
};
#endif

View file

@ -49,6 +49,17 @@ class TabDeckEditorVisualTabWidget : public QTabWidget
Q_OBJECT
public:
/**
* @brief Sub-tab order in the container; addNewTab() is called in this order.
*/
enum TabIndex
{
VisualDeckView,
VisualDatabaseDisplay,
DeckAnalytics,
SampleHand,
};
/**
* @brief Construct the tab widget with required models.
* @param parent Parent widget.

View file

@ -25,6 +25,11 @@ int DeckEditorSettings::getDefaultDeckEditorType() const
return getValue("defaultDeckEditorType", QString(), QString(), 1).toInt();
}
int DeckEditorSettings::getVdeStartupTab() const
{
return getValue("vdeStartupTab", QString(), QString(), VdeStartupTabContext).toInt();
}
void DeckEditorSettings::setOpenDeckInNewTab(bool _openDeckInNewTab)
{
setValue(_openDeckInNewTab, "openDeckInNewTab");
@ -47,6 +52,12 @@ void DeckEditorSettings::setDefaultDeckEditorType(int _defaultDeckEditorType)
setValue(_defaultDeckEditorType, "defaultDeckEditorType");
}
void DeckEditorSettings::setVdeStartupTab(int _vdeStartupTab)
{
setValue(_vdeStartupTab, "vdeStartupTab");
emit vdeStartupTabChanged(_vdeStartupTab);
}
int DeckEditorSettings::getCommanderSpellbookIntegrationEnabled() const
{
return getValue("commanderspellbookintegrationenabled", QString(), QString(),

View file

@ -13,6 +13,13 @@ enum commanderSpellbookIntegrationEnabledIndex
commanderSpellbookIntegrationEnabledIndexUnprompted,
};
enum VdeStartupTab
{
VdeStartupTabContext, ///< Match the opened deck: new decks show the database display, existing decks the deck view
VdeStartupTabDeckDisplay, ///< Always open the Visual Deck View
VdeStartupTabDatabaseDisplay, ///< Always open the Visual Database Display
};
class DeckEditorSettings : public SettingsManager, public IDeckEditorSettingsProvider
{
Q_OBJECT
@ -23,6 +30,7 @@ public:
[[nodiscard]] bool getBannerCardComboBoxVisible() const override;
[[nodiscard]] bool getTagsWidgetVisible() const override;
[[nodiscard]] int getDefaultDeckEditorType() const override;
[[nodiscard]] int getVdeStartupTab() const;
[[nodiscard]] int getCommanderSpellbookIntegrationEnabled() const;
[[nodiscard]] bool getCommanderSpellbookIntegrationUseOfficialBracketNames() const;
@ -30,6 +38,7 @@ public:
void setBannerCardComboBoxVisible(bool _bannerCardComboBoxVisible);
void setTagsWidgetVisible(bool _tagsWidgetVisible);
void setDefaultDeckEditorType(int _defaultDeckEditorType);
void setVdeStartupTab(int _vdeStartupTab);
void setCommanderSpellbookIntegrationEnabled(int _commanderSpellbookIntegrationEnabled);
void setCommanderSpellbookIntegrationUseOfficialBracketNames(bool _useOfficialBracketNames);
@ -38,6 +47,7 @@ signals:
void tagsWidgetVisibleChanged(bool visible);
void commanderSpellbookIntegrationEnabledChanged(int enabled);
void commanderSpellbookIntegrationUseOfficialBracketNamesChanged(bool useOfficialBracketNames);
void vdeStartupTabChanged(int vdeStartupTab);
public:
explicit DeckEditorSettings(const QString &settingPath, QObject *parent = nullptr);

View file

@ -400,6 +400,23 @@ TEST_F(SettingsDefaultsTest, DeckEditor_DefaultDeckEditorType_Default)
ASSERT_EQ(s.getDefaultDeckEditorType(), 1);
}
TEST_F(SettingsDefaultsTest, DeckEditor_VdeStartupTab_Default)
{
DeckEditorSettings s(settingsPath, nullptr);
ASSERT_EQ(s.getVdeStartupTab(), VdeStartupTabContext);
}
TEST_F(SettingsDefaultsTest, DeckEditor_VdeStartupTab_SetAndGet)
{
DeckEditorSettings s(settingsPath, nullptr);
s.setVdeStartupTab(VdeStartupTabDeckDisplay);
ASSERT_EQ(s.getVdeStartupTab(), VdeStartupTabDeckDisplay);
s.setVdeStartupTab(VdeStartupTabDatabaseDisplay);
ASSERT_EQ(s.getVdeStartupTab(), VdeStartupTabDatabaseDisplay);
s.setVdeStartupTab(VdeStartupTabContext);
ASSERT_EQ(s.getVdeStartupTab(), VdeStartupTabContext);
}
// --- NetworkSettings ---
TEST_F(SettingsDefaultsTest, Network_ClientID_Default)