mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-02 11:33:55 -07:00
Visual Deck Editor Base (#5834)
* Visual Deck Editor. * Lint. * Address comments. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
a55a287a9d
commit
42c56898d5
26 changed files with 1949 additions and 3 deletions
|
|
@ -44,6 +44,8 @@ set(cockatrice_SOURCES
|
||||||
src/client/tabs/tab_server.cpp
|
src/client/tabs/tab_server.cpp
|
||||||
src/client/tabs/tab_supervisor.cpp
|
src/client/tabs/tab_supervisor.cpp
|
||||||
src/client/tabs/tab_visual_database_display.cpp
|
src/client/tabs/tab_visual_database_display.cpp
|
||||||
|
src/client/tabs/visual_deck_editor/tab_deck_editor_visual.cpp
|
||||||
|
src/client/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp
|
||||||
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
src/client/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
||||||
src/client/tapped_out_interface.cpp
|
src/client/tapped_out_interface.cpp
|
||||||
src/client/translate_counter_name.cpp
|
src/client/translate_counter_name.cpp
|
||||||
|
|
@ -60,6 +62,9 @@ set(cockatrice_SOURCES
|
||||||
src/client/ui/widgets/cards/additional_info/color_identity_widget.cpp
|
src/client/ui/widgets/cards/additional_info/color_identity_widget.cpp
|
||||||
src/client/ui/widgets/cards/additional_info/mana_cost_widget.cpp
|
src/client/ui/widgets/cards/additional_info/mana_cost_widget.cpp
|
||||||
src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
|
src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp
|
||||||
|
src/client/ui/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
|
||||||
|
src/client/ui/widgets/cards/card_group_display_widgets/flat_card_group_display_widget.cpp
|
||||||
|
src/client/ui/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp
|
||||||
src/client/ui/widgets/cards/card_info_display_widget.cpp
|
src/client/ui/widgets/cards/card_info_display_widget.cpp
|
||||||
src/client/ui/widgets/cards/card_info_frame_widget.cpp
|
src/client/ui/widgets/cards/card_info_frame_widget.cpp
|
||||||
src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp
|
src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp
|
||||||
|
|
@ -67,6 +72,7 @@ set(cockatrice_SOURCES
|
||||||
src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
||||||
src/client/ui/widgets/cards/card_info_text_widget.cpp
|
src/client/ui/widgets/cards/card_info_text_widget.cpp
|
||||||
src/client/ui/widgets/cards/card_size_widget.cpp
|
src/client/ui/widgets/cards/card_size_widget.cpp
|
||||||
|
src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
|
||||||
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
src/client/ui/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
||||||
src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
||||||
|
|
@ -101,6 +107,7 @@ set(cockatrice_SOURCES
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
|
src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
||||||
src/client/ui/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
src/client/ui/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
||||||
|
src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
||||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
||||||
|
|
@ -149,6 +156,7 @@ set(cockatrice_SOURCES
|
||||||
src/game/board/counter_general.cpp
|
src/game/board/counter_general.cpp
|
||||||
src/game/cards/abstract_card_drag_item.cpp
|
src/game/cards/abstract_card_drag_item.cpp
|
||||||
src/game/cards/abstract_card_item.cpp
|
src/game/cards/abstract_card_item.cpp
|
||||||
|
src/game/cards/card_completer_proxy_model.cpp
|
||||||
src/game/cards/card_database.cpp
|
src/game/cards/card_database.cpp
|
||||||
src/game/cards/card_database_manager.cpp
|
src/game/cards/card_database_manager.cpp
|
||||||
src/game/cards/card_database_model.cpp
|
src/game/cards/card_database_model.cpp
|
||||||
|
|
@ -159,6 +167,7 @@ set(cockatrice_SOURCES
|
||||||
src/game/cards/card_info.cpp
|
src/game/cards/card_info.cpp
|
||||||
src/game/cards/card_item.cpp
|
src/game/cards/card_item.cpp
|
||||||
src/game/cards/card_list.cpp
|
src/game/cards/card_list.cpp
|
||||||
|
src/game/cards/card_search_model.cpp
|
||||||
src/game/deckview/deck_view.cpp
|
src/game/deckview/deck_view.cpp
|
||||||
src/game/deckview/deck_view_container.cpp
|
src/game/deckview/deck_view_container.cpp
|
||||||
src/game/filters/filter_builder.cpp
|
src/game/filters/filter_builder.cpp
|
||||||
|
|
@ -214,6 +223,7 @@ set(cockatrice_SOURCES
|
||||||
src/settings/shortcut_treeview.cpp
|
src/settings/shortcut_treeview.cpp
|
||||||
src/settings/shortcuts_settings.cpp
|
src/settings/shortcuts_settings.cpp
|
||||||
src/utility/card_info_comparator.cpp
|
src/utility/card_info_comparator.cpp
|
||||||
|
src/utility/levenshtein.cpp
|
||||||
src/utility/logger.cpp
|
src/utility/logger.cpp
|
||||||
src/utility/sequence_edit.cpp
|
src/utility/sequence_edit.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_server.h"
|
#include "tab_server.h"
|
||||||
#include "tab_visual_database_display.h"
|
#include "tab_visual_database_display.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
|
||||||
#include "visual_deck_storage/tab_deck_storage_visual.h"
|
#include "visual_deck_storage/tab_deck_storage_visual.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
@ -131,6 +133,9 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *
|
||||||
aTabDeckEditor = new QAction(this);
|
aTabDeckEditor = new QAction(this);
|
||||||
connect(aTabDeckEditor, &QAction::triggered, this, [this] { addDeckEditorTab(nullptr); });
|
connect(aTabDeckEditor, &QAction::triggered, this, [this] { addDeckEditorTab(nullptr); });
|
||||||
|
|
||||||
|
aTabVisualDeckEditor = new QAction(this);
|
||||||
|
connect(aTabVisualDeckEditor, &QAction::triggered, this, [this] { addVisualDeckEditorTab(nullptr); });
|
||||||
|
|
||||||
aTabVisualDeckStorage = new QAction(this);
|
aTabVisualDeckStorage = new QAction(this);
|
||||||
aTabVisualDeckStorage->setCheckable(true);
|
aTabVisualDeckStorage->setCheckable(true);
|
||||||
connect(aTabVisualDeckStorage, &QAction::triggered, this, &TabSupervisor::actTabVisualDeckStorage);
|
connect(aTabVisualDeckStorage, &QAction::triggered, this, &TabSupervisor::actTabVisualDeckStorage);
|
||||||
|
|
@ -180,6 +185,7 @@ void TabSupervisor::retranslateUi()
|
||||||
{
|
{
|
||||||
// tab menu actions
|
// tab menu actions
|
||||||
aTabDeckEditor->setText(tr("Deck Editor"));
|
aTabDeckEditor->setText(tr("Deck Editor"));
|
||||||
|
aTabVisualDeckEditor->setText(tr("Visual Deck Editor"));
|
||||||
aTabVisualDeckStorage->setText(tr("&Visual Deck Storage"));
|
aTabVisualDeckStorage->setText(tr("&Visual Deck Storage"));
|
||||||
aTabVisualDatabaseDisplay->setText(tr("Visual Database Display"));
|
aTabVisualDatabaseDisplay->setText(tr("Visual Database Display"));
|
||||||
aTabServer->setText(tr("Server"));
|
aTabServer->setText(tr("Server"));
|
||||||
|
|
@ -228,6 +234,7 @@ void TabSupervisor::refreshShortcuts()
|
||||||
{
|
{
|
||||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||||
aTabDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabDeckEditor"));
|
aTabDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabDeckEditor"));
|
||||||
|
aTabVisualDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckEditor"));
|
||||||
aTabVisualDeckStorage->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckStorage"));
|
aTabVisualDeckStorage->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckStorage"));
|
||||||
aTabServer->setShortcuts(shortcuts.getShortcut("Tabs/aTabServer"));
|
aTabServer->setShortcuts(shortcuts.getShortcut("Tabs/aTabServer"));
|
||||||
aTabAccount->setShortcuts(shortcuts.getShortcut("Tabs/aTabAccount"));
|
aTabAccount->setShortcuts(shortcuts.getShortcut("Tabs/aTabAccount"));
|
||||||
|
|
@ -375,6 +382,7 @@ void TabSupervisor::resetTabsMenu()
|
||||||
{
|
{
|
||||||
tabsMenu->clear();
|
tabsMenu->clear();
|
||||||
tabsMenu->addAction(aTabDeckEditor);
|
tabsMenu->addAction(aTabDeckEditor);
|
||||||
|
tabsMenu->addAction(aTabVisualDeckEditor);
|
||||||
tabsMenu->addSeparator();
|
tabsMenu->addSeparator();
|
||||||
tabsMenu->addAction(aTabVisualDeckStorage);
|
tabsMenu->addAction(aTabVisualDeckStorage);
|
||||||
tabsMenu->addAction(aTabVisualDatabaseDisplay);
|
tabsMenu->addAction(aTabVisualDatabaseDisplay);
|
||||||
|
|
@ -810,6 +818,19 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TabDeckEditorVisual *TabSupervisor::addVisualDeckEditorTab(const DeckLoader *deckToOpen)
|
||||||
|
{
|
||||||
|
auto *tab = new TabDeckEditorVisual(this);
|
||||||
|
if (deckToOpen)
|
||||||
|
tab->openDeck(new DeckLoader(*deckToOpen));
|
||||||
|
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
||||||
|
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addVisualDeckEditorTab);
|
||||||
|
myAddTab(tab);
|
||||||
|
deckEditorTabs.append(tab);
|
||||||
|
setCurrentWidget(tab);
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
|
||||||
TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab()
|
TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab()
|
||||||
{
|
{
|
||||||
auto *tab = new TabVisualDatabaseDisplay(this);
|
auto *tab = new TabVisualDatabaseDisplay(this);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include "abstract_tab_deck_editor.h"
|
#include "abstract_tab_deck_editor.h"
|
||||||
#include "api/edhrec/tab_edhrec.h"
|
#include "api/edhrec/tab_edhrec.h"
|
||||||
#include "tab_visual_database_display.h"
|
#include "tab_visual_database_display.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
|
||||||
#include "visual_deck_storage/tab_deck_storage_visual.h"
|
#include "visual_deck_storage/tab_deck_storage_visual.h"
|
||||||
|
|
||||||
#include <QAbstractButton>
|
#include <QAbstractButton>
|
||||||
|
|
@ -92,8 +94,8 @@ private:
|
||||||
QList<AbstractTabDeckEditor *> deckEditorTabs;
|
QList<AbstractTabDeckEditor *> deckEditorTabs;
|
||||||
bool isLocalGame;
|
bool isLocalGame;
|
||||||
|
|
||||||
QAction *aTabDeckEditor, *aTabVisualDeckStorage, *aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount,
|
QAction *aTabDeckEditor, *aTabVisualDeckEditor, *aTabVisualDeckStorage, *aTabVisualDatabaseDisplay, *aTabServer,
|
||||||
*aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog;
|
*aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog;
|
||||||
|
|
||||||
int myAddTab(Tab *tab, QAction *manager = nullptr);
|
int myAddTab(Tab *tab, QAction *manager = nullptr);
|
||||||
void addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager);
|
void addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager);
|
||||||
|
|
@ -150,6 +152,7 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
|
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
|
||||||
|
TabDeckEditorVisual *addVisualDeckEditorTab(const DeckLoader *deckToOpen);
|
||||||
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
|
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
|
||||||
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
|
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
|
||||||
void openReplay(GameReplay *replay);
|
void openReplay(GameReplay *replay);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,467 @@
|
||||||
|
#include "tab_deck_editor_visual.h"
|
||||||
|
|
||||||
|
#include "../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../deck/deck_stats_interface.h"
|
||||||
|
#include "../../../game/cards/card_database_model.h"
|
||||||
|
#include "../../../game/filters/filter_builder.h"
|
||||||
|
#include "../../../server/pending_command.h"
|
||||||
|
#include "../../../settings/cache_settings.h"
|
||||||
|
#include "../../ui/pixel_map_generator.h"
|
||||||
|
#include "../../ui/widgets/cards/card_info_frame_widget.h"
|
||||||
|
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||||
|
#include "../tab_deck_editor.h"
|
||||||
|
#include "../tab_supervisor.h"
|
||||||
|
#include "pb/command_deck_upload.pb.h"
|
||||||
|
#include "tab_deck_editor_visual_tab_widget.h"
|
||||||
|
#include "trice_limits.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPrintPreviewDialog>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QTreeView>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
TabDeckEditorVisual::TabDeckEditorVisual(TabSupervisor *_tabSupervisor) : AbstractTabDeckEditor(_tabSupervisor)
|
||||||
|
{
|
||||||
|
setObjectName("TabDeckEditorVisual");
|
||||||
|
|
||||||
|
createCentralFrame();
|
||||||
|
|
||||||
|
TabDeckEditorVisual::createMenus();
|
||||||
|
|
||||||
|
installEventFilter(this);
|
||||||
|
|
||||||
|
TabDeckEditorVisual::retranslateUi();
|
||||||
|
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||||
|
TabDeckEditorVisual::refreshShortcuts();
|
||||||
|
|
||||||
|
TabDeckEditorVisual::loadLayout();
|
||||||
|
databaseDisplayDockWidget->setHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::createCentralFrame()
|
||||||
|
{
|
||||||
|
centralWidget = new QWidget(this);
|
||||||
|
centralWidget->setObjectName("centralWidget");
|
||||||
|
|
||||||
|
centralFrame = new QVBoxLayout;
|
||||||
|
centralWidget->setLayout(centralFrame);
|
||||||
|
|
||||||
|
tabContainer = new TabDeckEditorVisualTabWidget(centralWidget, this, deckDockWidget->deckModel,
|
||||||
|
databaseDisplayDockWidget->databaseModel,
|
||||||
|
databaseDisplayDockWidget->databaseDisplayModel);
|
||||||
|
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChanged, this,
|
||||||
|
&TabDeckEditorVisual::changeModelIndexAndCardInfo);
|
||||||
|
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChangedDatabaseDisplay, this,
|
||||||
|
&AbstractTabDeckEditor::updateCard);
|
||||||
|
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClicked, this,
|
||||||
|
&TabDeckEditorVisual::processMainboardCardClick);
|
||||||
|
|
||||||
|
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClickedDatabaseDisplay, this,
|
||||||
|
&TabDeckEditorVisual::processCardClickDatabaseDisplay);
|
||||||
|
centralFrame->addWidget(tabContainer);
|
||||||
|
|
||||||
|
setCentralWidget(centralWidget);
|
||||||
|
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::onDeckChanged()
|
||||||
|
{
|
||||||
|
AbstractTabDeckEditor::onDeckChanged();
|
||||||
|
tabContainer->visualDeckView->decklistDataChanged(QModelIndex(), QModelIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::createMenus()
|
||||||
|
{
|
||||||
|
deckMenu = new DeckEditorMenu(this);
|
||||||
|
addTabMenu(deckMenu);
|
||||||
|
|
||||||
|
viewMenu = new QMenu(this);
|
||||||
|
|
||||||
|
cardInfoDockMenu = viewMenu->addMenu(QString());
|
||||||
|
deckDockMenu = viewMenu->addMenu(QString());
|
||||||
|
deckAnalyticsMenu = viewMenu->addMenu(QString());
|
||||||
|
filterDockMenu = viewMenu->addMenu(QString());
|
||||||
|
printingSelectorDockMenu = viewMenu->addMenu(QString());
|
||||||
|
|
||||||
|
aCardInfoDockVisible = cardInfoDockMenu->addAction(QString());
|
||||||
|
aCardInfoDockVisible->setCheckable(true);
|
||||||
|
connect(aCardInfoDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
|
||||||
|
aCardInfoDockFloating = cardInfoDockMenu->addAction(QString());
|
||||||
|
aCardInfoDockFloating->setCheckable(true);
|
||||||
|
connect(aCardInfoDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
|
||||||
|
|
||||||
|
aDeckDockVisible = deckDockMenu->addAction(QString());
|
||||||
|
aDeckDockVisible->setCheckable(true);
|
||||||
|
connect(aDeckDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
|
||||||
|
aDeckDockFloating = deckDockMenu->addAction(QString());
|
||||||
|
aDeckDockFloating->setCheckable(true);
|
||||||
|
connect(aDeckDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
|
||||||
|
|
||||||
|
aDeckAnalyticsDockVisible = deckAnalyticsMenu->addAction(QString());
|
||||||
|
aDeckAnalyticsDockVisible->setCheckable(true);
|
||||||
|
connect(aDeckAnalyticsDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
|
||||||
|
aDeckAnalyticsDockFloating = deckAnalyticsMenu->addAction(QString());
|
||||||
|
aDeckAnalyticsDockFloating->setCheckable(true);
|
||||||
|
connect(aDeckAnalyticsDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
|
||||||
|
|
||||||
|
aFilterDockVisible = filterDockMenu->addAction(QString());
|
||||||
|
aFilterDockVisible->setCheckable(true);
|
||||||
|
connect(aFilterDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
|
||||||
|
aFilterDockFloating = filterDockMenu->addAction(QString());
|
||||||
|
aFilterDockFloating->setCheckable(true);
|
||||||
|
connect(aFilterDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
|
||||||
|
|
||||||
|
aPrintingSelectorDockVisible = printingSelectorDockMenu->addAction(QString());
|
||||||
|
aPrintingSelectorDockVisible->setCheckable(true);
|
||||||
|
connect(aPrintingSelectorDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
|
||||||
|
aPrintingSelectorDockFloating = printingSelectorDockMenu->addAction(QString());
|
||||||
|
aPrintingSelectorDockFloating->setCheckable(true);
|
||||||
|
connect(aPrintingSelectorDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
|
||||||
|
|
||||||
|
viewMenu->addSeparator();
|
||||||
|
|
||||||
|
aResetLayout = viewMenu->addAction(QString());
|
||||||
|
connect(aResetLayout, SIGNAL(triggered()), this, SLOT(restartLayout()));
|
||||||
|
viewMenu->addAction(aResetLayout);
|
||||||
|
|
||||||
|
deckMenu->setSaveStatus(false);
|
||||||
|
|
||||||
|
addTabMenu(viewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TabDeckEditorVisual::getTabText() const
|
||||||
|
{
|
||||||
|
QString result = tr("Visual Deck: %1").arg(deckDockWidget->getSimpleDeckName());
|
||||||
|
if (modified)
|
||||||
|
result.prepend("* ");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::changeModelIndexAndCardInfo(const CardInfoPtr &activeCard)
|
||||||
|
{
|
||||||
|
updateCard(activeCard);
|
||||||
|
changeModelIndexToCard(activeCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::changeModelIndexToCard(const CardInfoPtr &activeCard)
|
||||||
|
{
|
||||||
|
QString cardName = activeCard->getName();
|
||||||
|
QModelIndex index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_MAIN);
|
||||||
|
if (!index.isValid()) {
|
||||||
|
index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_SIDE);
|
||||||
|
}
|
||||||
|
deckDockWidget->deckView->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance,
|
||||||
|
QString zoneName)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
actSwapCard(instance->getInfo(), zoneName);
|
||||||
|
} else if (event->button() == Qt::RightButton) {
|
||||||
|
actDecrementCard(instance->getInfo());
|
||||||
|
} else if (event->button() == Qt::MiddleButton) {
|
||||||
|
deckDockWidget->actRemoveCard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::processCardClickDatabaseDisplay(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
actAddCard(instance->getInfo());
|
||||||
|
} else if (event->button() == Qt::RightButton) {
|
||||||
|
actDecrementCard(instance->getInfo());
|
||||||
|
} else if (event->button() == Qt::MiddleButton) {
|
||||||
|
deckDockWidget->actRemoveCard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TabDeckEditorVisual::actSaveDeckAs()
|
||||||
|
{
|
||||||
|
// We have to disable the quick-add search bar or else it'll steal focus after dialog creation.
|
||||||
|
tabContainer->visualDeckView->searchBar->setEnabled(false);
|
||||||
|
auto result = AbstractTabDeckEditor::actSaveDeckAs();
|
||||||
|
tabContainer->visualDeckView->searchBar->setEnabled(true);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::showPrintingSelector()
|
||||||
|
{
|
||||||
|
printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getInfo(), DECK_ZONE_MAIN);
|
||||||
|
printingSelectorDockWidget->printingSelector->updateDisplay();
|
||||||
|
aPrintingSelectorDockVisible->setChecked(true);
|
||||||
|
printingSelectorDockWidget->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::restartLayout()
|
||||||
|
{
|
||||||
|
deckDockWidget->setVisible(true);
|
||||||
|
cardInfoDockWidget->setVisible(true);
|
||||||
|
filterDockWidget->setVisible(true);
|
||||||
|
|
||||||
|
deckDockWidget->setFloating(false);
|
||||||
|
cardInfoDockWidget->setFloating(false);
|
||||||
|
filterDockWidget->setFloating(false);
|
||||||
|
|
||||||
|
aCardInfoDockVisible->setChecked(true);
|
||||||
|
aDeckDockVisible->setChecked(true);
|
||||||
|
aFilterDockVisible->setChecked(true);
|
||||||
|
|
||||||
|
aCardInfoDockFloating->setChecked(false);
|
||||||
|
aDeckDockFloating->setChecked(false);
|
||||||
|
aFilterDockFloating->setChecked(false);
|
||||||
|
|
||||||
|
addDockWidget(static_cast<Qt::DockWidgetArea>(2), deckDockWidget);
|
||||||
|
addDockWidget(static_cast<Qt::DockWidgetArea>(2), cardInfoDockWidget);
|
||||||
|
addDockWidget(static_cast<Qt::DockWidgetArea>(1), deckAnalyticsDock);
|
||||||
|
addDockWidget(static_cast<Qt::DockWidgetArea>(2), filterDockWidget);
|
||||||
|
|
||||||
|
splitDockWidget(cardInfoDockWidget, deckDockWidget, Qt::Horizontal);
|
||||||
|
splitDockWidget(cardInfoDockWidget, filterDockWidget, Qt::Vertical);
|
||||||
|
splitDockWidget(searchAndDatabaseDock, deckAnalyticsDock, Qt::Vertical);
|
||||||
|
|
||||||
|
deckDockWidget->setMinimumWidth(360);
|
||||||
|
deckDockWidget->setMaximumWidth(360);
|
||||||
|
|
||||||
|
cardInfoDockWidget->setMinimumSize(250, 360);
|
||||||
|
cardInfoDockWidget->setMaximumSize(250, 360);
|
||||||
|
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::freeDocksSize()
|
||||||
|
{
|
||||||
|
deckDockWidget->setMinimumSize(100, 100);
|
||||||
|
deckDockWidget->setMaximumSize(5000, 5000);
|
||||||
|
|
||||||
|
cardInfoDockWidget->setMinimumSize(100, 100);
|
||||||
|
cardInfoDockWidget->setMaximumSize(5000, 5000);
|
||||||
|
|
||||||
|
filterDockWidget->setMinimumSize(100, 100);
|
||||||
|
filterDockWidget->setMaximumSize(5000, 5000);
|
||||||
|
|
||||||
|
databaseDisplayDockWidget->setMinimumSize(100, 100);
|
||||||
|
databaseDisplayDockWidget->setMaximumSize(1400, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::refreshShortcuts()
|
||||||
|
{
|
||||||
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||||
|
aResetLayout->setShortcuts(shortcuts.getShortcut("TabDeckEditorVisual/aResetLayout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::loadLayout()
|
||||||
|
{
|
||||||
|
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
||||||
|
auto &layoutState = layouts.getDeckEditorLayoutState();
|
||||||
|
if (layoutState.isNull()) {
|
||||||
|
restartLayout();
|
||||||
|
} else {
|
||||||
|
restoreState(layoutState);
|
||||||
|
restoreGeometry(layouts.getDeckEditorGeometry());
|
||||||
|
}
|
||||||
|
|
||||||
|
aCardInfoDockVisible->setChecked(!cardInfoDockWidget->isHidden());
|
||||||
|
aFilterDockVisible->setChecked(!filterDockWidget->isHidden());
|
||||||
|
aDeckDockVisible->setChecked(!deckDockWidget->isHidden());
|
||||||
|
aPrintingSelectorDockVisible->setChecked(!printingSelectorDockWidget->isHidden());
|
||||||
|
|
||||||
|
aCardInfoDockFloating->setEnabled(aCardInfoDockVisible->isChecked());
|
||||||
|
aDeckDockFloating->setEnabled(aDeckDockVisible->isChecked());
|
||||||
|
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
|
||||||
|
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
|
||||||
|
|
||||||
|
aCardInfoDockFloating->setChecked(cardInfoDockWidget->isFloating());
|
||||||
|
aFilterDockFloating->setChecked(filterDockWidget->isFloating());
|
||||||
|
aDeckDockFloating->setChecked(deckDockWidget->isFloating());
|
||||||
|
aPrintingSelectorDockFloating->setChecked(printingSelectorDockWidget->isFloating());
|
||||||
|
|
||||||
|
cardInfoDockWidget->setMinimumSize(layouts.getDeckEditorCardSize());
|
||||||
|
cardInfoDockWidget->setMaximumSize(layouts.getDeckEditorCardSize());
|
||||||
|
|
||||||
|
filterDockWidget->setMinimumSize(layouts.getDeckEditorFilterSize());
|
||||||
|
filterDockWidget->setMaximumSize(layouts.getDeckEditorFilterSize());
|
||||||
|
|
||||||
|
deckDockWidget->setMinimumSize(layouts.getDeckEditorDeckSize());
|
||||||
|
deckDockWidget->setMaximumSize(layouts.getDeckEditorDeckSize());
|
||||||
|
|
||||||
|
printingSelectorDockWidget->setMinimumSize(layouts.getDeckEditorPrintingSelectorSize());
|
||||||
|
printingSelectorDockWidget->setMaximumSize(layouts.getDeckEditorPrintingSelectorSize());
|
||||||
|
|
||||||
|
databaseDisplayDockWidget->setMinimumSize(100, 100);
|
||||||
|
databaseDisplayDockWidget->setMaximumSize(1400, 5000);
|
||||||
|
|
||||||
|
QTimer::singleShot(100, this, &TabDeckEditorVisual::freeDocksSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::retranslateUi()
|
||||||
|
{
|
||||||
|
deckMenu->setTitle(tr("&Visual Deck Editor"));
|
||||||
|
|
||||||
|
cardInfoDockWidget->setWindowTitle(tr("Card Info"));
|
||||||
|
deckDockWidget->setWindowTitle(tr("Deck"));
|
||||||
|
filterDockWidget->setWindowTitle(tr("Filters"));
|
||||||
|
|
||||||
|
viewMenu->setTitle(tr("&View"));
|
||||||
|
cardInfoDockMenu->setTitle(tr("Card Info"));
|
||||||
|
deckDockMenu->setTitle(tr("Deck"));
|
||||||
|
deckAnalyticsMenu->setTitle(tr("Deck Analytics"));
|
||||||
|
filterDockMenu->setTitle(tr("Filters"));
|
||||||
|
printingSelectorDockMenu->setTitle(tr("Printing"));
|
||||||
|
|
||||||
|
aCardInfoDockVisible->setText(tr("Visible"));
|
||||||
|
aCardInfoDockFloating->setText(tr("Floating"));
|
||||||
|
|
||||||
|
aDeckDockVisible->setText(tr("Visible"));
|
||||||
|
aDeckDockFloating->setText(tr("Floating"));
|
||||||
|
|
||||||
|
aDeckAnalyticsDockVisible->setText(tr("Visible"));
|
||||||
|
aDeckAnalyticsDockFloating->setText(tr("Floating"));
|
||||||
|
|
||||||
|
aFilterDockVisible->setText(tr("Visible"));
|
||||||
|
aFilterDockFloating->setText(tr("Floating"));
|
||||||
|
|
||||||
|
aPrintingSelectorDockVisible->setText(tr("Visible"));
|
||||||
|
aPrintingSelectorDockFloating->setText(tr("Floating"));
|
||||||
|
|
||||||
|
aResetLayout->setText(tr("Reset layout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method uses to sync docks state with menu items state
|
||||||
|
bool TabDeckEditorVisual::eventFilter(QObject *o, QEvent *e)
|
||||||
|
{
|
||||||
|
if (e->type() == QEvent::Close) {
|
||||||
|
if (o == cardInfoDockWidget) {
|
||||||
|
aCardInfoDockVisible->setChecked(false);
|
||||||
|
aCardInfoDockFloating->setEnabled(false);
|
||||||
|
} else if (o == deckDockWidget) {
|
||||||
|
aDeckDockVisible->setChecked(false);
|
||||||
|
aDeckDockFloating->setEnabled(false);
|
||||||
|
} else if (o == deckAnalyticsDock) {
|
||||||
|
aDeckAnalyticsDockVisible->setChecked(false);
|
||||||
|
aDeckAnalyticsDockFloating->setEnabled(false);
|
||||||
|
} else if (o == filterDockWidget) {
|
||||||
|
aFilterDockVisible->setChecked(false);
|
||||||
|
aFilterDockFloating->setEnabled(false);
|
||||||
|
} else if (o == printingSelectorDockWidget) {
|
||||||
|
aPrintingSelectorDockVisible->setChecked(false);
|
||||||
|
aPrintingSelectorDockFloating->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (o == this && e->type() == QEvent::Hide) {
|
||||||
|
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
||||||
|
layouts.setDeckEditorLayoutState(saveState());
|
||||||
|
layouts.setDeckEditorGeometry(saveGeometry());
|
||||||
|
layouts.setDeckEditorCardSize(cardInfoDockWidget->size());
|
||||||
|
layouts.setDeckEditorFilterSize(filterDockWidget->size());
|
||||||
|
layouts.setDeckEditorDeckSize(deckDockWidget->size());
|
||||||
|
layouts.setDeckEditorPrintingSelectorSize(printingSelectorDockWidget->size());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::dockVisibleTriggered()
|
||||||
|
{
|
||||||
|
QObject *o = sender();
|
||||||
|
if (o == aCardInfoDockVisible) {
|
||||||
|
cardInfoDockWidget->setHidden(!aCardInfoDockVisible->isChecked());
|
||||||
|
aCardInfoDockFloating->setEnabled(aCardInfoDockVisible->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aDeckDockVisible) {
|
||||||
|
deckDockWidget->setHidden(!aDeckDockVisible->isChecked());
|
||||||
|
aDeckDockFloating->setEnabled(aDeckDockVisible->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aDeckAnalyticsDockVisible) {
|
||||||
|
deckAnalyticsDock->setHidden(!aDeckAnalyticsDockVisible->isChecked());
|
||||||
|
aDeckAnalyticsDockFloating->setEnabled(aDeckAnalyticsDockVisible->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aFilterDockVisible) {
|
||||||
|
filterDockWidget->setHidden(!aFilterDockVisible->isChecked());
|
||||||
|
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aPrintingSelectorDockVisible) {
|
||||||
|
printingSelectorDockWidget->setHidden(!aPrintingSelectorDockVisible->isChecked());
|
||||||
|
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::dockFloatingTriggered()
|
||||||
|
{
|
||||||
|
QObject *o = sender();
|
||||||
|
if (o == aCardInfoDockFloating) {
|
||||||
|
cardInfoDockWidget->setFloating(aCardInfoDockFloating->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aDeckDockFloating) {
|
||||||
|
deckDockWidget->setFloating(aDeckDockFloating->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aDeckAnalyticsDockFloating) {
|
||||||
|
deckAnalyticsDock->setFloating(aDeckAnalyticsDockFloating->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aFilterDockFloating) {
|
||||||
|
filterDockWidget->setFloating(aFilterDockFloating->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == aPrintingSelectorDockFloating) {
|
||||||
|
printingSelectorDockWidget->setFloating(aPrintingSelectorDockFloating->isChecked());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisual::dockTopLevelChanged(bool topLevel)
|
||||||
|
{
|
||||||
|
QObject *o = sender();
|
||||||
|
if (o == cardInfoDockWidget) {
|
||||||
|
aCardInfoDockFloating->setChecked(topLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == deckDockWidget) {
|
||||||
|
aDeckDockFloating->setChecked(topLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == filterDockWidget) {
|
||||||
|
aFilterDockFloating->setChecked(topLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == deckAnalyticsDock) {
|
||||||
|
aDeckAnalyticsDockFloating->setChecked(topLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o == printingSelectorDockWidget) {
|
||||||
|
aPrintingSelectorDockFloating->setChecked(topLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef WINDOW_DECKEDITORVISUAL_H
|
||||||
|
#define WINDOW_DECKEDITORVISUAL_H
|
||||||
|
|
||||||
|
#include "../tab.h"
|
||||||
|
#include "tab_deck_editor_visual_tab_widget.h"
|
||||||
|
|
||||||
|
class TabDeckEditorVisual : public AbstractTabDeckEditor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected slots:
|
||||||
|
void loadLayout() override;
|
||||||
|
void restartLayout() override;
|
||||||
|
void freeDocksSize() override;
|
||||||
|
void refreshShortcuts() override;
|
||||||
|
|
||||||
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
|
void dockVisibleTriggered() override;
|
||||||
|
void dockFloatingTriggered() override;
|
||||||
|
void dockTopLevelChanged(bool topLevel) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TabDeckEditorVisualTabWidget *tabContainer;
|
||||||
|
|
||||||
|
QVBoxLayout *centralFrame;
|
||||||
|
QVBoxLayout *searchAndDatabaseFrame;
|
||||||
|
QHBoxLayout *searchLayout;
|
||||||
|
QDockWidget *searchAndDatabaseDock;
|
||||||
|
QDockWidget *deckAnalyticsDock;
|
||||||
|
QWidget *centralWidget;
|
||||||
|
QMenu *deckAnalyticsMenu;
|
||||||
|
QAction *aDeckAnalyticsDockVisible, *aDeckAnalyticsDockFloating;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabDeckEditorVisual(TabSupervisor *_tabSupervisor);
|
||||||
|
void retranslateUi() override;
|
||||||
|
QString getTabText() const override;
|
||||||
|
void changeModelIndexAndCardInfo(const CardInfoPtr &activeCard);
|
||||||
|
void changeModelIndexToCard(const CardInfoPtr &activeCard);
|
||||||
|
void createDeckAnalyticsDock();
|
||||||
|
void createMenus() override;
|
||||||
|
void createSearchAndDatabaseFrame();
|
||||||
|
void createCentralFrame();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onDeckChanged() override;
|
||||||
|
void showPrintingSelector() override;
|
||||||
|
void
|
||||||
|
processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||||
|
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
bool actSaveDeckAs() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
#include "tab_deck_editor_visual_tab_widget.h"
|
||||||
|
|
||||||
|
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
||||||
|
#include "../abstract_tab_deck_editor.h"
|
||||||
|
|
||||||
|
TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
|
||||||
|
AbstractTabDeckEditor *_deckEditor,
|
||||||
|
DeckListModel *_deckModel,
|
||||||
|
CardDatabaseModel *_cardDatabaseModel,
|
||||||
|
CardDatabaseDisplayModel *_cardDatabaseDisplayModel)
|
||||||
|
: QTabWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), cardDatabaseModel(_cardDatabaseModel),
|
||||||
|
cardDatabaseDisplayModel(_cardDatabaseDisplayModel)
|
||||||
|
{
|
||||||
|
this->setTabsClosable(true); // Enable tab closing
|
||||||
|
connect(this, &QTabWidget::tabCloseRequested, this, &TabDeckEditorVisualTabWidget::handleTabClose);
|
||||||
|
|
||||||
|
// Set up the layout and add tab widget
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
visualDeckView = new VisualDeckEditorWidget(this, deckModel);
|
||||||
|
visualDeckView->setObjectName("visualDeckView");
|
||||||
|
connect(visualDeckView, &VisualDeckEditorWidget::activeCardChanged, this,
|
||||||
|
&TabDeckEditorVisualTabWidget::onCardChanged);
|
||||||
|
connect(visualDeckView, &VisualDeckEditorWidget::cardClicked, this,
|
||||||
|
&TabDeckEditorVisualTabWidget::onCardClickedDeckEditor);
|
||||||
|
connect(visualDeckView, &VisualDeckEditorWidget::cardAdditionRequested, deckEditor,
|
||||||
|
&AbstractTabDeckEditor::actAddCard);
|
||||||
|
|
||||||
|
visualDatabaseDisplay =
|
||||||
|
new VisualDatabaseDisplayWidget(this, deckEditor, _cardDatabaseModel, _cardDatabaseDisplayModel);
|
||||||
|
visualDatabaseDisplay->setObjectName("visualDatabaseView");
|
||||||
|
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardHoveredDatabaseDisplay, this,
|
||||||
|
&TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay);
|
||||||
|
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardClickedDatabaseDisplay, this,
|
||||||
|
&TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay);
|
||||||
|
|
||||||
|
this->addNewTab(visualDeckView, tr("Visual Deck View"));
|
||||||
|
this->addNewTab(visualDatabaseDisplay, tr("Visual Database Display"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardChanged(CardInfoPtr activeCard)
|
||||||
|
{
|
||||||
|
emit cardChanged(activeCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(CardInfoPtr activeCard)
|
||||||
|
{
|
||||||
|
emit cardChangedDatabaseDisplay(activeCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardClickedDeckEditor(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance,
|
||||||
|
QString zoneName)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, instance, zoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit cardClickedDatabaseDisplay(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::addNewTab(QWidget *widget, const QString &title)
|
||||||
|
{
|
||||||
|
// Add new tab to the tab widget
|
||||||
|
this->addTab(widget, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::removeCurrentTab()
|
||||||
|
{
|
||||||
|
// Remove the currently selected tab
|
||||||
|
int currentIndex = this->currentIndex();
|
||||||
|
if (currentIndex != -1) {
|
||||||
|
this->removeTab(currentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::setTabTitle(int index, const QString &title)
|
||||||
|
{
|
||||||
|
// Set the title of the tab at the given index
|
||||||
|
if (index >= 0 && index < this->count()) {
|
||||||
|
this->setTabText(index, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *TabDeckEditorVisualTabWidget::getCurrentTab() const
|
||||||
|
{
|
||||||
|
// Return the currently selected tab widget
|
||||||
|
return this->currentWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TabDeckEditorVisualTabWidget::getTabCount() const
|
||||||
|
{
|
||||||
|
// Return the number of tabs
|
||||||
|
return this->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::handleTabClose(int index)
|
||||||
|
{
|
||||||
|
// Handle closing of the tab at the given index
|
||||||
|
QWidget *tab = this->widget(index);
|
||||||
|
this->removeTab(index);
|
||||||
|
delete tab; // Delete the tab's widget to free memory
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||||
|
#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../ui/widgets/printing_selector/printing_selector.h"
|
||||||
|
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
||||||
|
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||||
|
#include "../abstract_tab_deck_editor.h"
|
||||||
|
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class TabDeckEditorVisualTabWidget : public QTabWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabDeckEditorVisualTabWidget(QWidget *parent,
|
||||||
|
AbstractTabDeckEditor *_deckEditor,
|
||||||
|
DeckListModel *_deckModel,
|
||||||
|
CardDatabaseModel *_cardDatabaseModel,
|
||||||
|
CardDatabaseDisplayModel *_cardDatabaseDisplayModel);
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
void addNewTab(QWidget *widget, const QString &title);
|
||||||
|
void removeCurrentTab();
|
||||||
|
void setTabTitle(int index, const QString &title);
|
||||||
|
QWidget *getCurrentTab() const;
|
||||||
|
int getTabCount() const;
|
||||||
|
|
||||||
|
VisualDeckEditorWidget *visualDeckView;
|
||||||
|
VisualDatabaseDisplayWidget *visualDatabaseDisplay;
|
||||||
|
PrintingSelector *printingSelector;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onCardChanged(CardInfoPtr activeCard);
|
||||||
|
void onCardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
||||||
|
void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||||
|
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardChanged(CardInfoPtr activeCard);
|
||||||
|
void cardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||||
|
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVBoxLayout *layout; // Layout for the tab widget and other controls
|
||||||
|
AbstractTabDeckEditor *deckEditor;
|
||||||
|
DeckListModel *deckModel;
|
||||||
|
CardDatabaseModel *cardDatabaseModel;
|
||||||
|
CardDatabaseDisplayModel *cardDatabaseDisplayModel;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleTabClose(int index); // Slot for closing a tab
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
|
TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
|
||||||
: Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this))
|
: Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this))
|
||||||
{
|
{
|
||||||
connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addDeckEditorTab);
|
connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addVisualDeckEditorTab);
|
||||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
|
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
|
||||||
&TabDeckStorageVisual::actOpenLocalDeck);
|
&TabDeckStorageVisual::actOpenLocalDeck);
|
||||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this,
|
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include "card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *_deckListModel,
|
||||||
|
QString _zoneName,
|
||||||
|
QString _cardGroupCategory,
|
||||||
|
QString _activeGroupCriteria,
|
||||||
|
QStringList _activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *_cardSizeWidget)
|
||||||
|
: QWidget(parent), deckListModel(_deckListModel), zoneName(_zoneName), cardGroupCategory(_cardGroupCategory),
|
||||||
|
activeGroupCriteria(_activeGroupCriteria), activeSortCriteria(_activeSortCriteria),
|
||||||
|
cardSizeWidget(_cardSizeWidget)
|
||||||
|
{
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
setMinimumSize(QSize(0, 0));
|
||||||
|
|
||||||
|
banner = new BannerWidget(this, cardGroupCategory, Qt::Orientation::Vertical, bannerOpacity);
|
||||||
|
|
||||||
|
layout->addWidget(banner);
|
||||||
|
updateCardDisplays();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::updateCardDisplays()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CardInfoPtr> CardGroupDisplayWidget::getCardsMatchingGroup(QList<CardInfoPtr> cardsToSort)
|
||||||
|
{
|
||||||
|
cardsToSort = sortCardList(cardsToSort, activeSortCriteria, Qt::SortOrder::AscendingOrder);
|
||||||
|
|
||||||
|
QList<CardInfoPtr> activeList;
|
||||||
|
for (const CardInfoPtr &info : cardsToSort) {
|
||||||
|
if (info && info->getProperty(activeGroupCriteria) == cardGroupCategory) {
|
||||||
|
activeList.append(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CardInfoPtr> CardGroupDisplayWidget::sortCardList(QList<CardInfoPtr> cardsToSort,
|
||||||
|
const QStringList properties,
|
||||||
|
Qt::SortOrder order = Qt::AscendingOrder)
|
||||||
|
{
|
||||||
|
CardInfoComparator comparator(properties, order);
|
||||||
|
std::sort(cardsToSort.begin(), cardsToSort.end(), comparator);
|
||||||
|
|
||||||
|
return cardsToSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria)
|
||||||
|
{
|
||||||
|
if (activeSortCriteria != _activeSortCriteria) {
|
||||||
|
activeSortCriteria = _activeSortCriteria;
|
||||||
|
updateCardDisplays(); // Refresh display with new sorting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::onHover(CardInfoPtr card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
#define CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../../game/cards/card_database.h"
|
||||||
|
#include "../../general/display/banner_widget.h"
|
||||||
|
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../card_size_widget.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class CardGroupDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *deckListModel,
|
||||||
|
QString zoneName,
|
||||||
|
QString cardGroupCategory,
|
||||||
|
QString activeGroupCriteria,
|
||||||
|
QStringList activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *cardSizeWidget);
|
||||||
|
|
||||||
|
QList<CardInfoPtr> getCardsMatchingGroup(QList<CardInfoPtr> cardsToSort);
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
DeckListModel *deckListModel;
|
||||||
|
QString zoneName;
|
||||||
|
QString cardGroupCategory;
|
||||||
|
QString activeGroupCriteria;
|
||||||
|
QStringList activeSortCriteria;
|
||||||
|
CardSizeWidget *cardSizeWidget;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
QList<CardInfoPtr> sortCardList(QList<CardInfoPtr> cardsToSort, QStringList properties, Qt::SortOrder order);
|
||||||
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void onHover(CardInfoPtr card);
|
||||||
|
virtual void updateCardDisplays();
|
||||||
|
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void cardHovered(CardInfoPtr card);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
BannerWidget *banner;
|
||||||
|
};
|
||||||
|
#endif // CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include "flat_card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
FlatCardGroupDisplayWidget::FlatCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *_deckListModel,
|
||||||
|
QString _zoneName,
|
||||||
|
QString _cardGroupCategory,
|
||||||
|
QString _activeGroupCriteria,
|
||||||
|
QStringList _activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *_cardSizeWidget)
|
||||||
|
: CardGroupDisplayWidget(parent,
|
||||||
|
_deckListModel,
|
||||||
|
_zoneName,
|
||||||
|
_cardGroupCategory,
|
||||||
|
_activeGroupCriteria,
|
||||||
|
_activeSortCriteria,
|
||||||
|
bannerOpacity,
|
||||||
|
_cardSizeWidget)
|
||||||
|
{
|
||||||
|
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||||
|
banner->setBuddy(flowWidget);
|
||||||
|
|
||||||
|
layout->addWidget(flowWidget);
|
||||||
|
FlatCardGroupDisplayWidget::updateCardDisplays();
|
||||||
|
connect(deckListModel, &DeckListModel::dataChanged, this, &FlatCardGroupDisplayWidget::updateCardDisplays);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlatCardGroupDisplayWidget::updateCardDisplays()
|
||||||
|
{
|
||||||
|
// Retrieve and sort cards
|
||||||
|
QList<CardInfoPtr> cardsInZone = getCardsMatchingGroup(deckListModel->getCardsAsCardInfoPtrsForZone(zoneName));
|
||||||
|
|
||||||
|
// Show or hide widget
|
||||||
|
bool shouldBeVisible = !cardsInZone.isEmpty();
|
||||||
|
if (shouldBeVisible != isVisible()) {
|
||||||
|
setVisible(shouldBeVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve existing widgets
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> existingWidgets =
|
||||||
|
flowWidget->findChildren<CardInfoPictureWithTextOverlayWidget *>();
|
||||||
|
|
||||||
|
QHash<QString, QList<CardInfoPictureWithTextOverlayWidget *>> widgetMap;
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
|
||||||
|
widgetMap[widget->getInfo()->getName()].append(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> sortedWidgets;
|
||||||
|
QSet<CardInfoPictureWithTextOverlayWidget *> usedWidgets;
|
||||||
|
|
||||||
|
// Ensure widgets are ordered to match the sorted cards
|
||||||
|
for (const CardInfoPtr &card : cardsInZone) {
|
||||||
|
QString name = card->getName();
|
||||||
|
CardInfoPictureWithTextOverlayWidget *widget = nullptr;
|
||||||
|
|
||||||
|
if (!widgetMap[name].isEmpty()) {
|
||||||
|
// Reuse an existing widget
|
||||||
|
widget = widgetMap[name].takeFirst();
|
||||||
|
} else {
|
||||||
|
// Create a new widget if needed
|
||||||
|
widget = new CardInfoPictureWithTextOverlayWidget(flowWidget, true);
|
||||||
|
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||||
|
widget->setCard(card);
|
||||||
|
|
||||||
|
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
|
||||||
|
&FlatCardGroupDisplayWidget::onClick);
|
||||||
|
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this,
|
||||||
|
&FlatCardGroupDisplayWidget::onHover);
|
||||||
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget,
|
||||||
|
&CardInfoPictureWidget::setScaleFactor);
|
||||||
|
|
||||||
|
flowWidget->addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store in sorted order
|
||||||
|
sortedWidgets.append(widget);
|
||||||
|
usedWidgets.insert(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove extra widgets
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
|
||||||
|
if (!usedWidgets.contains(widget)) {
|
||||||
|
flowWidget->layout()->removeWidget(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **Reorder widgets in place**
|
||||||
|
for (int i = 0; i < sortedWidgets.size(); ++i) {
|
||||||
|
sortedWidgets[i]->setParent(nullptr); // Temporarily detach
|
||||||
|
}
|
||||||
|
for (int i = 0; i < sortedWidgets.size(); ++i) {
|
||||||
|
flowWidget->addWidget(sortedWidgets[i]); // Reattach in correct order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlatCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
#define FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../general/layout_containers/flow_widget.h"
|
||||||
|
#include "card_group_display_widget.h"
|
||||||
|
|
||||||
|
class FlatCardGroupDisplayWidget : public CardGroupDisplayWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FlatCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *deckListModel,
|
||||||
|
QString zoneName,
|
||||||
|
QString cardGroupCategory,
|
||||||
|
QString activeGroupCriteria,
|
||||||
|
QStringList activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *cardSizeWidget);
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateCardDisplays() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FlowWidget *flowWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include "overlapped_card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *_deckListModel,
|
||||||
|
QString _zoneName,
|
||||||
|
QString _cardGroupCategory,
|
||||||
|
QString _activeGroupCriteria,
|
||||||
|
QStringList _activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *_cardSizeWidget)
|
||||||
|
: CardGroupDisplayWidget(parent,
|
||||||
|
_deckListModel,
|
||||||
|
_zoneName,
|
||||||
|
_cardGroupCategory,
|
||||||
|
_activeGroupCriteria,
|
||||||
|
_activeSortCriteria,
|
||||||
|
bannerOpacity,
|
||||||
|
_cardSizeWidget)
|
||||||
|
{
|
||||||
|
overlapWidget = new OverlapWidget(this, 80, 1, 1, Qt::Vertical, true);
|
||||||
|
banner->setBuddy(overlapWidget);
|
||||||
|
|
||||||
|
layout->addWidget(overlapWidget);
|
||||||
|
OverlappedCardGroupDisplayWidget::updateCardDisplays();
|
||||||
|
connect(deckListModel, &DeckListModel::dataChanged, this, &OverlappedCardGroupDisplayWidget::updateCardDisplays);
|
||||||
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
|
||||||
|
[this]() { overlapWidget->adjustMaxColumnsAndRows(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::updateCardDisplays()
|
||||||
|
{
|
||||||
|
overlapWidget->setUpdatesEnabled(false);
|
||||||
|
// Retrieve and sort cards
|
||||||
|
QList<CardInfoPtr> cardsInZone = getCardsMatchingGroup(deckListModel->getCardsAsCardInfoPtrsForZone(zoneName));
|
||||||
|
|
||||||
|
// Show or hide widget
|
||||||
|
bool shouldBeVisible = !cardsInZone.isEmpty();
|
||||||
|
if (shouldBeVisible != isVisible()) {
|
||||||
|
setVisible(shouldBeVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve existing widgets
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> existingWidgets =
|
||||||
|
overlapWidget->findChildren<CardInfoPictureWithTextOverlayWidget *>();
|
||||||
|
|
||||||
|
QHash<QString, QList<CardInfoPictureWithTextOverlayWidget *>> widgetMap;
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
|
||||||
|
widgetMap[widget->getInfo()->getName()].append(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> sortedWidgets;
|
||||||
|
QSet<CardInfoPictureWithTextOverlayWidget *> usedWidgets;
|
||||||
|
|
||||||
|
// Ensure widgets are ordered to match the sorted cards
|
||||||
|
for (const CardInfoPtr &card : cardsInZone) {
|
||||||
|
QString name = card->getName();
|
||||||
|
CardInfoPictureWithTextOverlayWidget *widget = nullptr;
|
||||||
|
|
||||||
|
if (!widgetMap[name].isEmpty()) {
|
||||||
|
// Reuse an existing widget
|
||||||
|
widget = widgetMap[name].takeFirst();
|
||||||
|
} else {
|
||||||
|
// Create a new widget if needed
|
||||||
|
widget = new CardInfoPictureWithTextOverlayWidget(overlapWidget, true);
|
||||||
|
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||||
|
widget->setCard(card);
|
||||||
|
|
||||||
|
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
|
||||||
|
&OverlappedCardGroupDisplayWidget::onClick);
|
||||||
|
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this,
|
||||||
|
&OverlappedCardGroupDisplayWidget::onHover);
|
||||||
|
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget,
|
||||||
|
&CardInfoPictureWidget::setScaleFactor);
|
||||||
|
|
||||||
|
overlapWidget->addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store in sorted order
|
||||||
|
sortedWidgets.append(widget);
|
||||||
|
usedWidgets.insert(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove extra widgets
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
|
||||||
|
if (!usedWidgets.contains(widget)) {
|
||||||
|
overlapWidget->layout()->removeWidget(widget);
|
||||||
|
delete widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **Reorder widgets in place**
|
||||||
|
for (int i = 0; i < sortedWidgets.size(); ++i) {
|
||||||
|
sortedWidgets[i]->setParent(nullptr); // Temporarily detach
|
||||||
|
}
|
||||||
|
for (int i = 0; i < sortedWidgets.size(); ++i) {
|
||||||
|
overlapWidget->addWidget(sortedWidgets[i]); // Reattach in correct order
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure proper layering
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *widget : sortedWidgets) {
|
||||||
|
widget->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
overlapWidget->adjustMaxColumnsAndRows();
|
||||||
|
overlapWidget->setUpdatesEnabled(true);
|
||||||
|
overlapWidget->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
|
||||||
|
overlapWidget->resize(event->size());
|
||||||
|
overlapWidget->adjustMaxColumnsAndRows();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
#define OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../general/layout_containers/overlap_widget.h"
|
||||||
|
#include "card_group_display_widget.h"
|
||||||
|
|
||||||
|
class OverlappedCardGroupDisplayWidget : public CardGroupDisplayWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OverlappedCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *deckListModel,
|
||||||
|
QString zoneName,
|
||||||
|
QString cardGroupCategory,
|
||||||
|
QString activeGroupCriteria,
|
||||||
|
QStringList activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
CardSizeWidget *cardSizeWidget);
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateCardDisplays() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OverlapWidget *overlapWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
@ -61,6 +61,7 @@ CardInfoFrameWidget::CardInfoFrameWidget(const QString &cardName, QWidget *paren
|
||||||
|
|
||||||
setViewMode(SettingsCache::instance().getCardInfoViewMode());
|
setViewMode(SettingsCache::instance().getCardInfoViewMode());
|
||||||
|
|
||||||
|
// TODO: Change this to be by UUID
|
||||||
setCard(CardDatabaseManager::getInstance()->getCard(cardName));
|
setCard(CardDatabaseManager::getInstance()->getCard(cardName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
#include "deck_card_zone_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../utility/card_info_comparator.h"
|
||||||
|
#include "card_group_display_widgets/flat_card_group_display_widget.h"
|
||||||
|
#include "card_group_display_widgets/overlapped_card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *_deckListModel,
|
||||||
|
QString _zoneName,
|
||||||
|
QString _activeGroupCriteria,
|
||||||
|
QStringList _activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
int subBannerOpacity,
|
||||||
|
CardSizeWidget *_cardSizeWidget)
|
||||||
|
: QWidget(parent), deckListModel(_deckListModel), zoneName(_zoneName), activeGroupCriteria(_activeGroupCriteria),
|
||||||
|
activeSortCriteria(_activeSortCriteria), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity),
|
||||||
|
cardSizeWidget(_cardSizeWidget)
|
||||||
|
{
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
banner = new BannerWidget(this, zoneName, Qt::Orientation::Vertical, bannerOpacity);
|
||||||
|
layout->addWidget(banner);
|
||||||
|
|
||||||
|
cardGroupContainer = new QWidget(this);
|
||||||
|
cardGroupLayout = new QVBoxLayout(cardGroupContainer);
|
||||||
|
cardGroupContainer->setLayout(cardGroupLayout);
|
||||||
|
layout->addWidget(cardGroupContainer);
|
||||||
|
|
||||||
|
banner->setBuddy(cardGroupContainer);
|
||||||
|
|
||||||
|
displayCards();
|
||||||
|
connect(deckListModel, &DeckListModel::dataChanged, this, &DeckCardZoneDisplayWidget::displayCards);
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
for (QObject *child : layout->children()) {
|
||||||
|
QWidget *widget = qobject_cast<QWidget *>(child);
|
||||||
|
if (widget) {
|
||||||
|
widget->setMaximumWidth(width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card, zoneName);
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::onHover(CardInfoPtr card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::displayCards()
|
||||||
|
{
|
||||||
|
addCardGroupIfItDoesNotExist();
|
||||||
|
deleteCardGroupIfItDoesNotExist();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::refreshDisplayType(const QString &_displayType)
|
||||||
|
{
|
||||||
|
displayType = _displayType;
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = cardGroupLayout->takeAt(0)) != nullptr) {
|
||||||
|
if (item->widget()) {
|
||||||
|
item->widget()->deleteLater();
|
||||||
|
} else if (item->layout()) {
|
||||||
|
delete item->layout();
|
||||||
|
}
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We gotta wait for all the deleteLater's to finish so we fire after the next event cycle
|
||||||
|
|
||||||
|
auto timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, this, [this]() { displayCards(); });
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::addCardGroupIfItDoesNotExist()
|
||||||
|
{
|
||||||
|
QList<CardGroupDisplayWidget *> cardGroupsDisplayWidgets =
|
||||||
|
cardGroupContainer->findChildren<CardGroupDisplayWidget *>();
|
||||||
|
|
||||||
|
QList<QString> cardGroups = getGroupCriteriaValueList();
|
||||||
|
|
||||||
|
for (QString cardGroup : cardGroups) {
|
||||||
|
bool found = false;
|
||||||
|
for (CardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
|
||||||
|
if (cardGroupDisplayWidget->cardGroupCategory == cardGroup) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayType == "overlap") {
|
||||||
|
auto *display_widget = new OverlappedCardGroupDisplayWidget(
|
||||||
|
cardGroupContainer, deckListModel, zoneName, cardGroup, activeGroupCriteria, activeSortCriteria,
|
||||||
|
subBannerOpacity, cardSizeWidget);
|
||||||
|
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, display_widget,
|
||||||
|
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
|
||||||
|
cardGroupLayout->addWidget(display_widget);
|
||||||
|
} else if (displayType == "flat") {
|
||||||
|
auto *display_widget = new FlatCardGroupDisplayWidget(cardGroupContainer, deckListModel, zoneName,
|
||||||
|
cardGroup, activeGroupCriteria, activeSortCriteria,
|
||||||
|
subBannerOpacity, cardSizeWidget);
|
||||||
|
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, display_widget,
|
||||||
|
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
|
||||||
|
cardGroupLayout->addWidget(display_widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::deleteCardGroupIfItDoesNotExist()
|
||||||
|
{
|
||||||
|
QList<CardGroupDisplayWidget *> cardGroupsDisplayWidgets =
|
||||||
|
cardGroupContainer->findChildren<CardGroupDisplayWidget *>();
|
||||||
|
|
||||||
|
QList<QString> validGroups = getGroupCriteriaValueList();
|
||||||
|
|
||||||
|
for (CardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
|
||||||
|
if (!validGroups.contains(cardGroupDisplayWidget->cardGroupCategory)) {
|
||||||
|
cardGroupLayout->removeWidget(cardGroupDisplayWidget);
|
||||||
|
cardGroupDisplayWidget->deleteLater(); // Properly delete the widget after the event loop cycles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged(QString _activeGroupCriteria)
|
||||||
|
{
|
||||||
|
activeGroupCriteria = _activeGroupCriteria;
|
||||||
|
displayCards();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria)
|
||||||
|
{
|
||||||
|
activeSortCriteria = _activeSortCriteria;
|
||||||
|
emit activeSortCriteriaChanged(activeSortCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> DeckCardZoneDisplayWidget::getGroupCriteriaValueList()
|
||||||
|
{
|
||||||
|
QList<QString> groupCriteriaValues;
|
||||||
|
|
||||||
|
QList<CardInfoPtr> cardsInZone = deckListModel->getCardsAsCardInfoPtrsForZone(zoneName);
|
||||||
|
|
||||||
|
for (CardInfoPtr cardInZone : cardsInZone) {
|
||||||
|
groupCriteriaValues.append(cardInZone->getProperty(activeGroupCriteria));
|
||||||
|
}
|
||||||
|
|
||||||
|
groupCriteriaValues.removeDuplicates();
|
||||||
|
groupCriteriaValues.sort();
|
||||||
|
|
||||||
|
return groupCriteriaValues;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||||
|
#define DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../general/display/banner_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_widget.h"
|
||||||
|
#include "card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "card_size_widget.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckCardZoneDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
|
DeckListModel *deckListModel,
|
||||||
|
QString zoneName,
|
||||||
|
QString activeGroupCriteria,
|
||||||
|
QStringList activeSortCriteria,
|
||||||
|
int bannerOpacity,
|
||||||
|
int subBannerOpacity,
|
||||||
|
CardSizeWidget *_cardSizeWidget);
|
||||||
|
DeckListModel *deckListModel;
|
||||||
|
QString zoneName;
|
||||||
|
void addCardsToOverlapWidget();
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void onHover(CardInfoPtr card);
|
||||||
|
void displayCards();
|
||||||
|
void refreshDisplayType(const QString &displayType);
|
||||||
|
void addCardGroupIfItDoesNotExist();
|
||||||
|
void deleteCardGroupIfItDoesNotExist();
|
||||||
|
void onActiveGroupCriteriaChanged(QString activeGroupCriteria);
|
||||||
|
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
||||||
|
QList<QString> getGroupCriteriaValueList();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card, QString zoneName);
|
||||||
|
void cardHovered(CardInfoPtr card);
|
||||||
|
void activeSortCriteriaChanged(QStringList activeSortCriteria);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString activeGroupCriteria;
|
||||||
|
QStringList activeSortCriteria;
|
||||||
|
int bannerOpacity = 20;
|
||||||
|
int subBannerOpacity = 10;
|
||||||
|
CardSizeWidget *cardSizeWidget;
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
BannerWidget *banner;
|
||||||
|
QWidget *cardGroupContainer;
|
||||||
|
QVBoxLayout *cardGroupLayout;
|
||||||
|
QString displayType = "flat";
|
||||||
|
OverlapWidget *overlapWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||||
|
|
@ -309,6 +309,8 @@ void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck)
|
||||||
deckView->expandAll();
|
deckView->expandAll();
|
||||||
|
|
||||||
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
||||||
|
|
||||||
|
emit deckChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckLoader *DeckEditorDeckDockWidget::getDeckList()
|
DeckLoader *DeckEditorDeckDockWidget::getDeckList()
|
||||||
|
|
@ -325,6 +327,7 @@ void DeckEditorDeckDockWidget::cleanDeck()
|
||||||
nameEdit->setText(QString());
|
nameEdit->setText(QString());
|
||||||
commentsEdit->setText(QString());
|
commentsEdit->setText(QString());
|
||||||
hashLabel->setText(QString());
|
hashLabel->setText(QString());
|
||||||
|
emit deckChanged();
|
||||||
updateBannerCardComboBox();
|
updateBannerCardComboBox();
|
||||||
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,315 @@
|
||||||
|
#include "visual_deck_editor_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../deck/deck_loader.h"
|
||||||
|
#include "../../../../game/cards/card_completer_proxy_model.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../game/cards/card_database_model.h"
|
||||||
|
#include "../../../../game/cards/card_search_model.h"
|
||||||
|
#include "../../../../main.h"
|
||||||
|
#include "../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../../layouts/overlap_layout.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../cards/deck_card_zone_display_widget.h"
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_control_widget.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||||
|
: QWidget(parent), deckListModel(_deckListModel)
|
||||||
|
{
|
||||||
|
connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged);
|
||||||
|
|
||||||
|
// The Main Widget and Main Layout, which contain a single Widget: The Scroll Area
|
||||||
|
setMinimumSize(0, 0);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
mainLayout = new QVBoxLayout(this);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
mainLayout->setContentsMargins(9, 0, 9, 5);
|
||||||
|
mainLayout->setSpacing(0);
|
||||||
|
|
||||||
|
searchContainer = new QWidget(this);
|
||||||
|
searchLayout = new QHBoxLayout(searchContainer);
|
||||||
|
searchContainer->setLayout(searchLayout);
|
||||||
|
|
||||||
|
searchBar = new QLineEdit(this);
|
||||||
|
connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() {
|
||||||
|
if (!searchBar->hasFocus())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CardInfoPtr card = CardDatabaseManager::getInstance()->getCard(searchBar->text());
|
||||||
|
if (card) {
|
||||||
|
emit cardAdditionRequested(card);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setFocusProxy(searchBar);
|
||||||
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
|
||||||
|
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
||||||
|
cardDatabaseDisplayModel = new CardDatabaseDisplayModel(this);
|
||||||
|
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
|
||||||
|
CardSearchModel *searchModel = new CardSearchModel(cardDatabaseDisplayModel, this);
|
||||||
|
|
||||||
|
proxyModel = new CardCompleterProxyModel(this);
|
||||||
|
proxyModel->setSourceModel(searchModel);
|
||||||
|
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
proxyModel->setFilterRole(Qt::DisplayRole);
|
||||||
|
|
||||||
|
completer = new QCompleter(proxyModel, this);
|
||||||
|
completer->setCompletionRole(Qt::DisplayRole);
|
||||||
|
completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
completer->setFilterMode(Qt::MatchContains);
|
||||||
|
completer->setMaxVisibleItems(15);
|
||||||
|
searchBar->setCompleter(completer);
|
||||||
|
|
||||||
|
// Update suggestions dynamically
|
||||||
|
connect(searchBar, &QLineEdit::textEdited, searchModel, &CardSearchModel::updateSearchResults);
|
||||||
|
connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) {
|
||||||
|
// Ensure substring matching
|
||||||
|
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
|
||||||
|
proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
|
||||||
|
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
completer->complete(); // Force the dropdown to appear
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(completer, static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::activated), this,
|
||||||
|
[=, this](const QString &completion) {
|
||||||
|
// Prevent the text from changing automatically when navigating with arrow keys
|
||||||
|
if (searchBar->text() != completion) {
|
||||||
|
searchBar->setText(completion); // Set the completion explicitly
|
||||||
|
searchBar->setCursorPosition(searchBar->text().length()); // Move cursor to the end
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure that the text stays consistent during selection
|
||||||
|
connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) {
|
||||||
|
if (searchBar->hasFocus() && !searchBar->completer()->popup()->isVisible()) {
|
||||||
|
// Allow text to change when typing, but not when navigating the completer
|
||||||
|
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
|
||||||
|
proxyModel->setFilterRegularExpression(
|
||||||
|
QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Search button functionality
|
||||||
|
searchPushButton = new QPushButton(this);
|
||||||
|
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() {
|
||||||
|
CardInfoPtr card = CardDatabaseManager::getInstance()->getCard(searchBar->text());
|
||||||
|
if (card) {
|
||||||
|
emit cardAdditionRequested(card);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
searchLayout->addWidget(searchBar);
|
||||||
|
searchLayout->addWidget(searchPushButton);
|
||||||
|
|
||||||
|
mainLayout->addWidget(searchContainer);
|
||||||
|
|
||||||
|
groupAndSortContainer = new QWidget(this);
|
||||||
|
groupAndSortLayout = new QHBoxLayout(groupAndSortContainer);
|
||||||
|
groupAndSortLayout->setAlignment(Qt::AlignLeft);
|
||||||
|
groupAndSortContainer->setLayout(groupAndSortLayout);
|
||||||
|
|
||||||
|
groupByComboBox = new QComboBox();
|
||||||
|
QStringList groupProperties = {"maintype", "colors", "cmc", "name"};
|
||||||
|
groupByComboBox->addItems(groupProperties);
|
||||||
|
groupByComboBox->setMinimumWidth(300);
|
||||||
|
connect(groupByComboBox, QOverload<const QString &>::of(&QComboBox::currentTextChanged), this,
|
||||||
|
&VisualDeckEditorWidget::actChangeActiveGroupCriteria);
|
||||||
|
actChangeActiveGroupCriteria();
|
||||||
|
|
||||||
|
sortCriteriaButton = new SettingsButtonWidget(this);
|
||||||
|
|
||||||
|
sortLabel = new QLabel(sortCriteriaButton);
|
||||||
|
sortLabel->setWordWrap(true);
|
||||||
|
|
||||||
|
QStringList sortProperties = {"colors", "cmc", "name", "maintype"};
|
||||||
|
sortByListWidget = new QListWidget();
|
||||||
|
sortByListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
sortByListWidget->setDragDropMode(QAbstractItemView::InternalMove);
|
||||||
|
sortByListWidget->setDefaultDropAction(Qt::MoveAction);
|
||||||
|
|
||||||
|
for (const QString &property : sortProperties) {
|
||||||
|
QListWidgetItem *item = new QListWidgetItem(property, sortByListWidget);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sortByListWidget->model(), &QAbstractItemModel::rowsMoved, this,
|
||||||
|
&VisualDeckEditorWidget::actChangeActiveSortCriteria);
|
||||||
|
actChangeActiveSortCriteria();
|
||||||
|
|
||||||
|
sortByListWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
sortCriteriaButton->addSettingsWidget(sortLabel);
|
||||||
|
sortCriteriaButton->addSettingsWidget(sortByListWidget);
|
||||||
|
|
||||||
|
displayTypeButton = new QPushButton(this);
|
||||||
|
connect(displayTypeButton, &QPushButton::clicked, this, &VisualDeckEditorWidget::updateDisplayType);
|
||||||
|
|
||||||
|
groupAndSortLayout->addWidget(groupByComboBox);
|
||||||
|
groupAndSortLayout->addWidget(sortCriteriaButton);
|
||||||
|
groupAndSortLayout->addWidget(displayTypeButton);
|
||||||
|
|
||||||
|
scrollArea = new QScrollArea();
|
||||||
|
scrollArea->setWidgetResizable(true);
|
||||||
|
scrollArea->setMinimumSize(0, 0);
|
||||||
|
|
||||||
|
// Set scrollbar policies
|
||||||
|
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
|
zoneContainer = new QWidget(scrollArea);
|
||||||
|
zoneContainerLayout = new QVBoxLayout(zoneContainer);
|
||||||
|
zoneContainer->setLayout(zoneContainerLayout);
|
||||||
|
scrollArea->addScrollBarWidget(zoneContainer, Qt::AlignHCenter);
|
||||||
|
scrollArea->setWidget(zoneContainer);
|
||||||
|
|
||||||
|
updateZoneWidgets();
|
||||||
|
|
||||||
|
cardSizeWidget = new CardSizeWidget(this);
|
||||||
|
|
||||||
|
mainLayout->addWidget(groupAndSortContainer);
|
||||||
|
mainLayout->addWidget(scrollArea);
|
||||||
|
mainLayout->addWidget(cardSizeWidget);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
|
||||||
|
searchPushButton->setText(tr("Quick search and add card"));
|
||||||
|
displayTypeButton->setText(tr("Flat Layout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::updateZoneWidgets()
|
||||||
|
{
|
||||||
|
addZoneIfDoesNotExist();
|
||||||
|
deleteZoneIfDoesNotExist();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::updateDisplayType()
|
||||||
|
{
|
||||||
|
// Toggle the display type
|
||||||
|
currentDisplayType = (currentDisplayType == DisplayType::Overlap) ? DisplayType::Flat : DisplayType::Overlap;
|
||||||
|
|
||||||
|
// Update UI and emit signal
|
||||||
|
switch (currentDisplayType) {
|
||||||
|
case DisplayType::Flat:
|
||||||
|
emit displayTypeChanged("flat");
|
||||||
|
displayTypeButton->setText(tr("Flat Layout"));
|
||||||
|
break;
|
||||||
|
case DisplayType::Overlap:
|
||||||
|
emit displayTypeChanged("overlap");
|
||||||
|
displayTypeButton->setText(tr("Overlap Layout"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::addZoneIfDoesNotExist()
|
||||||
|
{
|
||||||
|
QList<DeckCardZoneDisplayWidget *> cardZoneDisplayWidgets =
|
||||||
|
zoneContainer->findChildren<DeckCardZoneDisplayWidget *>();
|
||||||
|
for (const QString &zone : *deckListModel->getZones()) {
|
||||||
|
bool found = false;
|
||||||
|
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
|
||||||
|
if (displayWidget->zoneName == zone) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DeckCardZoneDisplayWidget *zoneDisplayWidget = new DeckCardZoneDisplayWidget(
|
||||||
|
zoneContainer, deckListModel, zone, activeGroupCriteria, activeSortCriteria, 20, 10, cardSizeWidget);
|
||||||
|
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover);
|
||||||
|
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this, &VisualDeckEditorWidget::onCardClick);
|
||||||
|
connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget,
|
||||||
|
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
|
||||||
|
connect(this, &VisualDeckEditorWidget::activeGroupCriteriaChanged, zoneDisplayWidget,
|
||||||
|
&DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged);
|
||||||
|
connect(this, &VisualDeckEditorWidget::displayTypeChanged, zoneDisplayWidget,
|
||||||
|
&DeckCardZoneDisplayWidget::refreshDisplayType);
|
||||||
|
zoneContainerLayout->addWidget(zoneDisplayWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::deleteZoneIfDoesNotExist()
|
||||||
|
{
|
||||||
|
QList<DeckCardZoneDisplayWidget *> cardZoneDisplayWidgets =
|
||||||
|
zoneContainer->findChildren<DeckCardZoneDisplayWidget *>();
|
||||||
|
for (DeckCardZoneDisplayWidget *displayWidget : cardZoneDisplayWidgets) {
|
||||||
|
bool found = false;
|
||||||
|
for (const QString &zone : *deckListModel->getZones()) {
|
||||||
|
if (displayWidget->zoneName == zone) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
zoneContainerLayout->removeWidget(displayWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
zoneContainer->setMaximumWidth(scrollArea->viewport()->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::actChangeActiveGroupCriteria()
|
||||||
|
{
|
||||||
|
activeGroupCriteria = groupByComboBox->currentText();
|
||||||
|
emit activeGroupCriteriaChanged(activeGroupCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::actChangeActiveSortCriteria()
|
||||||
|
{
|
||||||
|
QStringList selectedCriteria;
|
||||||
|
for (int i = 0; i < sortByListWidget->count(); ++i) {
|
||||||
|
QListWidgetItem *item = sortByListWidget->item(i);
|
||||||
|
selectedCriteria.append(item->text()); // Collect user-defined sort order
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSortCriteria = selectedCriteria;
|
||||||
|
|
||||||
|
emit activeSortCriteriaChanged(selectedCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight)
|
||||||
|
{
|
||||||
|
// Might use these at some point.
|
||||||
|
Q_UNUSED(topLeft);
|
||||||
|
Q_UNUSED(bottomRight);
|
||||||
|
// Necessary to delay this in this manner else the updateDisplay will nuke widgets while their onClick event
|
||||||
|
// hasn't returned yet. Interval of 0 means QT will schedule this after the current event loop has finished.
|
||||||
|
updateZoneWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::onHover(CardInfoPtr hoveredCard)
|
||||||
|
{
|
||||||
|
emit activeCardChanged(hoveredCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::onCardClick(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance,
|
||||||
|
QString zoneName)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, instance, zoneName);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef VISUAL_DECK_EDITOR_H
|
||||||
|
#define VISUAL_DECK_EDITOR_H
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../game/cards/card_completer_proxy_model.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_model.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../cards/card_size_widget.h"
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_control_widget.h"
|
||||||
|
#include "../quick_settings/settings_button_widget.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
enum class DisplayType
|
||||||
|
{
|
||||||
|
Flat,
|
||||||
|
Overlap
|
||||||
|
};
|
||||||
|
|
||||||
|
class VisualDeckEditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VisualDeckEditorWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||||
|
void retranslateUi();
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
void setDeckList(const DeckList &_deckListModel);
|
||||||
|
|
||||||
|
QLineEdit *searchBar;
|
||||||
|
CardSizeWidget *cardSizeWidget;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight);
|
||||||
|
void updateZoneWidgets();
|
||||||
|
void updateDisplayType();
|
||||||
|
void addZoneIfDoesNotExist();
|
||||||
|
void deleteZoneIfDoesNotExist();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void activeCardChanged(CardInfoPtr activeCard);
|
||||||
|
void activeGroupCriteriaChanged(QString activeGroupCriteria);
|
||||||
|
void activeSortCriteriaChanged(QStringList activeSortCriteria);
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||||
|
void cardAdditionRequested(CardInfoPtr card);
|
||||||
|
void displayTypeChanged(QString displayType);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void onHover(CardInfoPtr hoveredCard);
|
||||||
|
void onCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||||
|
void actChangeActiveGroupCriteria();
|
||||||
|
void actChangeActiveSortCriteria();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deckListModel;
|
||||||
|
QVBoxLayout *mainLayout;
|
||||||
|
QWidget *searchContainer;
|
||||||
|
QHBoxLayout *searchLayout;
|
||||||
|
CardDatabaseModel *cardDatabaseModel;
|
||||||
|
CardDatabaseDisplayModel *cardDatabaseDisplayModel;
|
||||||
|
CardCompleterProxyModel *proxyModel;
|
||||||
|
QCompleter *completer;
|
||||||
|
QPushButton *searchPushButton;
|
||||||
|
DisplayType currentDisplayType = DisplayType::Overlap;
|
||||||
|
QPushButton *displayTypeButton;
|
||||||
|
QWidget *groupAndSortContainer;
|
||||||
|
QHBoxLayout *groupAndSortLayout;
|
||||||
|
QComboBox *groupByComboBox;
|
||||||
|
QString activeGroupCriteria = "maintype";
|
||||||
|
SettingsButtonWidget *sortCriteriaButton;
|
||||||
|
QLabel *sortLabel;
|
||||||
|
QListWidget *sortByListWidget;
|
||||||
|
QStringList activeSortCriteria = {"name", "cmc", "colors", "maintype"};
|
||||||
|
QScrollArea *scrollArea;
|
||||||
|
QWidget *zoneContainer;
|
||||||
|
QVBoxLayout *zoneContainerLayout;
|
||||||
|
// OverlapControlWidget *overlapControlWidget;
|
||||||
|
QWidget *container;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VISUAL_DECK_EDITOR_H
|
||||||
18
cockatrice/src/game/cards/card_completer_proxy_model.cpp
Normal file
18
cockatrice/src/game/cards/card_completer_proxy_model.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "card_completer_proxy_model.h"
|
||||||
|
|
||||||
|
CardCompleterProxyModel::CardCompleterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CardCompleterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
|
{
|
||||||
|
if (filterRegularExpression().pattern().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||||
|
QString data = index.data(Qt::DisplayRole).toString();
|
||||||
|
|
||||||
|
// Ensure substring matching
|
||||||
|
return data.contains(filterRegularExpression());
|
||||||
|
}
|
||||||
16
cockatrice/src/game/cards/card_completer_proxy_model.h
Normal file
16
cockatrice/src/game/cards/card_completer_proxy_model.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef CARD_COMPLETER_PROXY_MODEL_H
|
||||||
|
#define CARD_COMPLETER_PROXY_MODEL_H
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
class CardCompleterProxyModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CardCompleterProxyModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CARD_COMPLETER_PROXY_MODEL_H
|
||||||
71
cockatrice/src/game/cards/card_search_model.cpp
Normal file
71
cockatrice/src/game/cards/card_search_model.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "card_search_model.h"
|
||||||
|
|
||||||
|
#include "../../utility/levenshtein.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
CardSearchModel::CardSearchModel(CardDatabaseDisplayModel *sourceModel, QObject *parent)
|
||||||
|
: QAbstractListModel(parent), sourceModel(sourceModel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CardSearchModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
return searchResults.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant CardSearchModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid() || index.row() >= searchResults.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return searchResults.at(index.row()).card->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardSearchModel::updateSearchResults(const QString &query)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
searchResults.clear();
|
||||||
|
|
||||||
|
if (query.isEmpty() || !sourceModel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set the filter for the display model
|
||||||
|
sourceModel->setCardName(query);
|
||||||
|
|
||||||
|
// Collect matching cards and compute Levenshtein distance
|
||||||
|
for (int i = 0; i < sourceModel->rowCount(); ++i) {
|
||||||
|
QModelIndex modelIndex = sourceModel->index(i, 0);
|
||||||
|
QModelIndex sourceIndex = sourceModel->mapToSource(modelIndex);
|
||||||
|
CardDatabaseModel *sourceDbModel = qobject_cast<CardDatabaseModel *>(sourceModel->sourceModel());
|
||||||
|
|
||||||
|
if (!sourceDbModel || !sourceIndex.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CardInfoPtr card = sourceDbModel->getCard(sourceIndex.row());
|
||||||
|
|
||||||
|
if (!card)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int distance = levenshteinDistance(query.toLower(), card->getName().toLower());
|
||||||
|
searchResults.append({card, distance});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by Levenshtein distance (lower distance = better match)
|
||||||
|
std::sort(searchResults.begin(), searchResults.end(),
|
||||||
|
[](const SearchResult &a, const SearchResult &b) { return a.distance < b.distance; });
|
||||||
|
|
||||||
|
// Keep only the top 5 results
|
||||||
|
if (searchResults.size() > 10)
|
||||||
|
searchResults = searchResults.mid(0, 10);
|
||||||
|
|
||||||
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0));
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
30
cockatrice/src/game/cards/card_search_model.h
Normal file
30
cockatrice/src/game/cards/card_search_model.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef CARD_SEARCH_MODEL_H
|
||||||
|
#define CARD_SEARCH_MODEL_H
|
||||||
|
|
||||||
|
#include "card_database_model.h"
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
class CardSearchModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CardSearchModel(CardDatabaseDisplayModel *sourceModel, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
void updateSearchResults(const QString &query); // Update results based on input
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SearchResult
|
||||||
|
{
|
||||||
|
CardInfoPtr card;
|
||||||
|
int distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
CardDatabaseDisplayModel *sourceModel;
|
||||||
|
QList<SearchResult> searchResults;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CARD_SEARCH_MODEL_H
|
||||||
25
cockatrice/src/utility/levenshtein.cpp
Normal file
25
cockatrice/src/utility/levenshtein.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "levenshtein.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
int levenshteinDistance(const QString &s1, const QString &s2)
|
||||||
|
{
|
||||||
|
int len1 = s1.size();
|
||||||
|
int len2 = s2.size();
|
||||||
|
std::vector<std::vector<int>> dp(len1 + 1, std::vector<int>(len2 + 1));
|
||||||
|
|
||||||
|
for (int i = 0; i <= len1; i++)
|
||||||
|
dp[i][0] = i;
|
||||||
|
for (int j = 0; j <= len2; j++)
|
||||||
|
dp[0][j] = j;
|
||||||
|
|
||||||
|
for (int i = 1; i <= len1; i++) {
|
||||||
|
for (int j = 1; j <= len2; j++) {
|
||||||
|
int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;
|
||||||
|
dp[i][j] = std::min({dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[len1][len2];
|
||||||
|
}
|
||||||
8
cockatrice/src/utility/levenshtein.h
Normal file
8
cockatrice/src/utility/levenshtein.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef LEVENSHTEIN_H
|
||||||
|
#define LEVENSHTEIN_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
int levenshteinDistance(const QString &s1, const QString &s2);
|
||||||
|
|
||||||
|
#endif // LEVENSHTEIN_H
|
||||||
Loading…
Add table
Add a link
Reference in a new issue