mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-18 00:12:15 -07:00
Visual Deck Editor.
This commit is contained in:
parent
13d18986b2
commit
0c73768c79
32 changed files with 3474 additions and 0 deletions
|
|
@ -25,6 +25,8 @@
|
||||||
#include "tab_replays.h"
|
#include "tab_replays.h"
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_server.h"
|
#include "tab_server.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>
|
||||||
|
|
@ -804,6 +806,14 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
|
||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TabDeckEditorVisual *TabSupervisor::addVisualDeckEditorTab()
|
||||||
|
{
|
||||||
|
TabDeckEditorVisual *tab = new TabDeckEditorVisual(this);
|
||||||
|
myAddTab(tab);
|
||||||
|
setCurrentWidget(tab);
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
|
||||||
TabEdhRec *TabSupervisor::addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander)
|
TabEdhRec *TabSupervisor::addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander)
|
||||||
{
|
{
|
||||||
auto *tab = new TabEdhRec(this);
|
auto *tab = new TabEdhRec(this);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#define TAB_SUPERVISOR_H
|
#define TAB_SUPERVISOR_H
|
||||||
|
|
||||||
#include "../../deck/deck_loader.h"
|
#include "../../deck/deck_loader.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual.h"
|
||||||
|
#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
|
||||||
#include "../../server/user/user_list_proxy.h"
|
#include "../../server/user/user_list_proxy.h"
|
||||||
#include "abstract_tab_deck_editor.h"
|
#include "abstract_tab_deck_editor.h"
|
||||||
#include "api/edhrec/tab_edhrec.h"
|
#include "api/edhrec/tab_edhrec.h"
|
||||||
|
|
@ -150,6 +152,8 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
|
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
|
||||||
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
|
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
|
||||||
|
TabDeckStorageVisual *addVisualDeckStorageTab();
|
||||||
|
TabDeckEditorVisual *addVisualDeckEditorTab();
|
||||||
void openReplay(GameReplay *replay);
|
void openReplay(GameReplay *replay);
|
||||||
void maximizeMainWindow();
|
void maximizeMainWindow();
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,151 @@
|
||||||
|
#ifndef WINDOW_DECKEDITORVISUAL_H
|
||||||
|
#define WINDOW_DECKEDITORVISUAL_H
|
||||||
|
|
||||||
|
#include "../../../deck/custom_line_edit.h"
|
||||||
|
#include "../../game_logic/key_signals.h"
|
||||||
|
#include "../tab.h"
|
||||||
|
#include "../tab_deck_editor.h"
|
||||||
|
#include "tab_deck_editor_visual_tab_widget.h"
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
class TabDeckEditorVisual : public Tab
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void updateName(const QString &name);
|
||||||
|
void updateComments();
|
||||||
|
void updateHash();
|
||||||
|
void updateCardInfoLeft(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
|
void updateCardInfoRight(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
|
void updateSearch(const QString &search);
|
||||||
|
void databaseCustomMenu(QPoint point);
|
||||||
|
|
||||||
|
void actNewDeck();
|
||||||
|
void actLoadDeck();
|
||||||
|
bool actSaveDeck();
|
||||||
|
bool actSaveDeckAs();
|
||||||
|
void actLoadDeckFromClipboard();
|
||||||
|
void actSaveDeckToClipboard();
|
||||||
|
void actSaveDeckToClipboardRaw();
|
||||||
|
void actPrintDeck();
|
||||||
|
void actExportDeckDecklist();
|
||||||
|
void actAnalyzeDeckDeckstats();
|
||||||
|
void actAnalyzeDeckTappedout();
|
||||||
|
|
||||||
|
void actClearFilterAll();
|
||||||
|
void actClearFilterOne();
|
||||||
|
|
||||||
|
void actSwapCard();
|
||||||
|
void actAddCard();
|
||||||
|
void actAddCardToSideboard();
|
||||||
|
void actRemoveCard();
|
||||||
|
void actIncrement();
|
||||||
|
void actDecrement();
|
||||||
|
void actDecrementCard();
|
||||||
|
void actDecrementCardFromSideboard();
|
||||||
|
void copyDatabaseCellContents();
|
||||||
|
|
||||||
|
void saveDeckRemoteFinished(const Response &r);
|
||||||
|
void filterViewCustomContextMenu(const QPoint &point);
|
||||||
|
void filterRemove(QAction *action);
|
||||||
|
|
||||||
|
void loadLayout();
|
||||||
|
void restartLayout();
|
||||||
|
void freeDocksSize();
|
||||||
|
void refreshShortcuts();
|
||||||
|
|
||||||
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
|
void dockVisibleTriggered();
|
||||||
|
void dockFloatingTriggered();
|
||||||
|
void dockTopLevelChanged(bool topLevel);
|
||||||
|
void saveDbHeaderState();
|
||||||
|
void setSaveStatus(bool newStatus);
|
||||||
|
void showSearchSyntaxHelp();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CardInfoPtr currentCardInfo() const;
|
||||||
|
void changeModelIndexToCard(CardInfoPtr activeCard);
|
||||||
|
void addCardHelper(QString zoneName);
|
||||||
|
void addCardInfo(CardInfoPtr info, QString zoneName);
|
||||||
|
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
||||||
|
void decrementCardHelper(QString zoneName);
|
||||||
|
void recursiveExpand(const QModelIndex &index);
|
||||||
|
|
||||||
|
QWidget *parent;
|
||||||
|
|
||||||
|
CardDatabaseModel *databaseModel;
|
||||||
|
CardDatabaseDisplayModel *databaseDisplayModel;
|
||||||
|
DeckListModel *deckModel;
|
||||||
|
QTreeView *databaseView;
|
||||||
|
|
||||||
|
TabDeckEditorVisualTabWidget *tabContainer;
|
||||||
|
|
||||||
|
QTreeView *deckView;
|
||||||
|
KeySignals deckViewKeySignals;
|
||||||
|
CardInfoFrameWidget *cardInfo;
|
||||||
|
|
||||||
|
SearchLineEdit *searchEdit;
|
||||||
|
KeySignals searchKeySignals;
|
||||||
|
|
||||||
|
QLabel *nameLabel;
|
||||||
|
LineEditUnfocusable *nameEdit;
|
||||||
|
QLabel *commentsLabel;
|
||||||
|
QTextEdit *commentsEdit;
|
||||||
|
QLabel *hashLabel1;
|
||||||
|
LineEditUnfocusable *hashLabel;
|
||||||
|
FilterTreeModel *filterModel;
|
||||||
|
QTreeView *filterView;
|
||||||
|
KeySignals filterViewKeySignals;
|
||||||
|
QWidget *filterBox;
|
||||||
|
|
||||||
|
QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *deckAnalyticsMenu, *filterDockMenu, *analyzeDeckMenu,
|
||||||
|
*saveDeckToClipboardMenu;
|
||||||
|
QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard,
|
||||||
|
*aSaveDeckToClipboardRaw, *aPrintDeck, *aExportDeckDecklist, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout,
|
||||||
|
*aClose;
|
||||||
|
QAction *aClearFilterAll, *aClearFilterOne;
|
||||||
|
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement;
|
||||||
|
QAction *aResetLayout;
|
||||||
|
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating,
|
||||||
|
*aDeckAnalyticsDockFloating, *aDeckAnalyticsDockVisible, *aFilterDockVisible, *aFilterDockFloating;
|
||||||
|
|
||||||
|
bool modified;
|
||||||
|
QVBoxLayout *centralFrame;
|
||||||
|
QVBoxLayout *searchAndDatabaseFrame;
|
||||||
|
QHBoxLayout *searchLayout;
|
||||||
|
QDockWidget *searchAndDatabaseDock;
|
||||||
|
QDockWidget *cardInfoDock;
|
||||||
|
QDockWidget *deckAnalyticsDock;
|
||||||
|
QDockWidget *deckDock;
|
||||||
|
QDockWidget *filterDock;
|
||||||
|
QWidget *centralWidget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabDeckEditorVisual(TabSupervisor *_tabSupervisor, QWidget *parent = nullptr);
|
||||||
|
~TabDeckEditorVisual() override;
|
||||||
|
void retranslateUi() override;
|
||||||
|
QString getTabText() const override;
|
||||||
|
void setDeck(DeckLoader *_deckLoader);
|
||||||
|
void setModified(bool _windowModified);
|
||||||
|
bool confirmClose();
|
||||||
|
void createDeckDock();
|
||||||
|
void createCardInfoDock();
|
||||||
|
void createDeckAnalyticsDock();
|
||||||
|
void createFiltersDock();
|
||||||
|
void createMenus();
|
||||||
|
void createSearchAndDatabaseFrame();
|
||||||
|
void createCentralFrame();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setCurrentCardInfo(CardInfoPtr activeCard);
|
||||||
|
void changeModelIndexAndCardInfo(CardInfoPtr activeCard);
|
||||||
|
void processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void processSideboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
signals:
|
||||||
|
void deckEditorClosing(TabDeckEditorVisual *tab);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include "tab_deck_editor_visual_database_search_tab.h"
|
||||||
|
|
||||||
|
#include "../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../main.h"
|
||||||
|
|
||||||
|
TabDeckEditorVisualDatabaseSearchTab::TabDeckEditorVisualDatabaseSearchTab(TabSupervisor *_tabSupervisor,
|
||||||
|
QWidget *_parent)
|
||||||
|
: Tab(_tabSupervisor), parent(_parent)
|
||||||
|
{
|
||||||
|
// Set up the layout and add tab widget
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
this->setLayout(layout);
|
||||||
|
|
||||||
|
visualDeckView = new VisualDeckEditorWidget(this, this->deckModel);
|
||||||
|
visualDeckView->setObjectName("visualDeckView");
|
||||||
|
visualDeckView->updateDisplay();
|
||||||
|
|
||||||
|
layout->addWidget(visualDeckView);
|
||||||
|
}
|
||||||
|
TabDeckEditorVisualDatabaseSearchTab::~TabDeckEditorVisualDatabaseSearchTab()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::updateCardInfoLeft(const QModelIndex ¤t, const QModelIndex &previous)
|
||||||
|
{
|
||||||
|
(void)current;
|
||||||
|
(void)previous;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::updateCardInfoRight(const QModelIndex ¤t, const QModelIndex &previous)
|
||||||
|
{
|
||||||
|
(void)current;
|
||||||
|
(void)previous;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::updateSearch(const QString &search)
|
||||||
|
{
|
||||||
|
(void)search;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::databaseCustomMenu(QPoint point)
|
||||||
|
{
|
||||||
|
(void)point;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actClearFilterAll()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actClearFilterOne()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actSwapCard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actAddCard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actAddCardToSideboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actRemoveCard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actIncrement()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actDecrement()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actDecrementCard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::actDecrementCardFromSideboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::copyDatabaseCellContents()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::filterViewCustomContextMenu(const QPoint &point)
|
||||||
|
{
|
||||||
|
(void)point;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::filterRemove(QAction *action)
|
||||||
|
{
|
||||||
|
(void)action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::saveDbHeaderState()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::setSaveStatus(bool newStatus)
|
||||||
|
{
|
||||||
|
(void)newStatus;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::showSearchSyntaxHelp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CardInfoPtr TabDeckEditorVisualDatabaseSearchTab::currentCardInfo() const
|
||||||
|
{
|
||||||
|
const QModelIndex currentIndex = databaseView->selectionModel()->currentIndex();
|
||||||
|
if (!currentIndex.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString cardName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
|
||||||
|
|
||||||
|
return CardDatabaseManager::getInstance()->getCard(cardName);
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::addCardHelper(QString zoneName)
|
||||||
|
{
|
||||||
|
(void)zoneName;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::offsetCountAtIndex(const QModelIndex &idx, int offset)
|
||||||
|
{
|
||||||
|
(void)idx;
|
||||||
|
(void)offset;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::decrementCardHelper(QString zoneName)
|
||||||
|
{
|
||||||
|
(void)zoneName;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::recursiveExpand(const QModelIndex &index)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::retranslateUi()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::setDeck(DeckLoader *_deckLoader)
|
||||||
|
{
|
||||||
|
(void)_deckLoader;
|
||||||
|
}
|
||||||
|
void TabDeckEditorVisualDatabaseSearchTab::setModified(bool _windowModified)
|
||||||
|
{
|
||||||
|
(void)_windowModified;
|
||||||
|
}
|
||||||
|
bool TabDeckEditorVisualDatabaseSearchTab::confirmClose()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
#ifndef TAB_DECK_EDITOR_VISUAL_DATABASE_SEARCH_TAB_H
|
||||||
|
#define TAB_DECK_EDITOR_VISUAL_DATABASE_SEARCH_TAB_H
|
||||||
|
#include "../../../client/game_logic/key_signals.h"
|
||||||
|
#include "../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../game/cards/card_database.h"
|
||||||
|
#include "../../../game/cards/card_database_model.h"
|
||||||
|
#include "../../ui/widgets/cards/card_info_frame_widget.h"
|
||||||
|
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
|
||||||
|
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||||
|
#include "../tab.h"
|
||||||
|
#include "../tab_deck_editor.h"
|
||||||
|
|
||||||
|
#include <QTreeView>
|
||||||
|
|
||||||
|
class TabDeckEditorVisualDatabaseSearchTab : public Tab
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void updateCardInfoLeft(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
|
void updateCardInfoRight(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
|
void updateSearch(const QString &search);
|
||||||
|
void databaseCustomMenu(QPoint point);
|
||||||
|
|
||||||
|
void actClearFilterAll();
|
||||||
|
void actClearFilterOne();
|
||||||
|
|
||||||
|
void actSwapCard();
|
||||||
|
void actAddCard();
|
||||||
|
void actAddCardToSideboard();
|
||||||
|
void actRemoveCard();
|
||||||
|
void actIncrement();
|
||||||
|
void actDecrement();
|
||||||
|
void actDecrementCard();
|
||||||
|
void actDecrementCardFromSideboard();
|
||||||
|
void copyDatabaseCellContents();
|
||||||
|
|
||||||
|
void filterViewCustomContextMenu(const QPoint &point);
|
||||||
|
void filterRemove(QAction *action);
|
||||||
|
|
||||||
|
void saveDbHeaderState();
|
||||||
|
void setSaveStatus(bool newStatus);
|
||||||
|
void showSearchSyntaxHelp();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *parent;
|
||||||
|
CardInfoPtr currentCardInfo() const;
|
||||||
|
void addCardHelper(QString zoneName);
|
||||||
|
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
||||||
|
void decrementCardHelper(QString zoneName);
|
||||||
|
void recursiveExpand(const QModelIndex &index);
|
||||||
|
|
||||||
|
CardDatabaseModel *databaseModel;
|
||||||
|
CardDatabaseDisplayModel *databaseDisplayModel;
|
||||||
|
DeckListModel *deckModel;
|
||||||
|
QTreeView *databaseView;
|
||||||
|
|
||||||
|
VisualDeckEditorWidget *visualDeckView;
|
||||||
|
CardInfoFrameWidget *cardInfo;
|
||||||
|
SearchLineEdit *searchEdit;
|
||||||
|
KeySignals searchKeySignals;
|
||||||
|
|
||||||
|
FilterTreeModel *filterModel;
|
||||||
|
QTreeView *filterView;
|
||||||
|
KeySignals filterViewKeySignals;
|
||||||
|
QWidget *filterBox;
|
||||||
|
|
||||||
|
QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *filterDockMenu;
|
||||||
|
QAction *aClose;
|
||||||
|
QAction *aClearFilterAll, *aClearFilterOne;
|
||||||
|
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement;
|
||||||
|
QAction *aResetLayout;
|
||||||
|
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating,
|
||||||
|
*aDeckAnalyticsDockFloating, *aDeckAnalyticsDockVisible, *aFilterDockVisible, *aFilterDockFloating;
|
||||||
|
|
||||||
|
bool modified;
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
QVBoxLayout *searchAndDatabaseFrame;
|
||||||
|
QHBoxLayout *searchLayout;
|
||||||
|
QDockWidget *searchAndDatabaseDock;
|
||||||
|
QDockWidget *cardInfoDock;
|
||||||
|
QDockWidget *deckDock;
|
||||||
|
QDockWidget *filterDock;
|
||||||
|
QWidget *centralWidget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabDeckEditorVisualDatabaseSearchTab(TabSupervisor *_tabSupervisor, QWidget *_parent);
|
||||||
|
~TabDeckEditorVisualDatabaseSearchTab() override;
|
||||||
|
void retranslateUi() override;
|
||||||
|
void setDeck(DeckLoader *_deckLoader);
|
||||||
|
void setModified(bool _windowModified);
|
||||||
|
bool confirmClose();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void deckEditorClosing(TabDeckEditorVisualDatabaseSearchTab *tab);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TAB_DECK_EDITOR_VISUAL_DATABASE_SEARCH_TAB_H
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
//
|
||||||
|
// Created by ascor on 10/12/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TAB_DECK_EDITOR_VISUAL_DECK_CARDS_TAB_H
|
||||||
|
#define TAB_DECK_EDITOR_VISUAL_DECK_CARDS_TAB_H
|
||||||
|
|
||||||
|
#endif // TAB_DECK_EDITOR_VISUAL_DECK_CARDS_TAB_H
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
//
|
||||||
|
// Created by ascor on 10/12/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TAB_DECK_EDITOR_VISUAL_DECK_STATS_TAB_H
|
||||||
|
#define TAB_DECK_EDITOR_VISUAL_DECK_STATS_TAB_H
|
||||||
|
|
||||||
|
#endif // TAB_DECK_EDITOR_VISUAL_DECK_STATS_TAB_H
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
#include "tab_deck_editor_visual_tab_widget.h"
|
||||||
|
|
||||||
|
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
||||||
|
|
||||||
|
TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
|
||||||
|
DeckListModel *model,
|
||||||
|
CardDatabaseModel *card_database_model,
|
||||||
|
CardDatabaseDisplayModel *card_database_display_model)
|
||||||
|
: QTabWidget(parent), deckModel(model), cardDatabaseModel(card_database_model),
|
||||||
|
cardDatabaseDisplayModel(card_database_display_model)
|
||||||
|
{
|
||||||
|
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, this->deckModel);
|
||||||
|
visualDeckView->setObjectName("visualDeckView");
|
||||||
|
visualDeckView->updateDisplay();
|
||||||
|
connect(visualDeckView, SIGNAL(activeCardChanged(CardInfoPtr)), this, SLOT(onCardChanged(CardInfoPtr)));
|
||||||
|
connect(visualDeckView, SIGNAL(mainboardCardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onMainboardCardClickedDeckEditor(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(visualDeckView, SIGNAL(sideboardCardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onSideboardCardClickedDeckEditor(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
|
||||||
|
visualDatabaseDisplay =
|
||||||
|
new VisualDatabaseDisplayWidget(this, this->cardDatabaseModel, this->cardDatabaseDisplayModel);
|
||||||
|
visualDatabaseDisplay->setObjectName("visualDatabaseView");
|
||||||
|
visualDatabaseDisplay->updateDisplay();
|
||||||
|
connect(visualDatabaseDisplay, SIGNAL(cardHoveredDatabaseDisplay(CardInfoPtr)), this,
|
||||||
|
SLOT(onCardChangedDatabaseDisplay(CardInfoPtr)));
|
||||||
|
connect(visualDatabaseDisplay,
|
||||||
|
SIGNAL(cardClickedDatabaseDisplay(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onCardClickedDatabaseDisplay(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
|
||||||
|
deckAnalytics = new DeckAnalyticsWidget(this, this->deckModel);
|
||||||
|
deckAnalytics->setObjectName("deckAnalytics");
|
||||||
|
// deckAnalytics->analyzeManaCurve();
|
||||||
|
|
||||||
|
this->addNewTab(visualDeckView, "Visual Deck View");
|
||||||
|
this->addNewTab(visualDatabaseDisplay, "Visual Database Display");
|
||||||
|
this->addNewTab(deckAnalytics, "Deck Analytics");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardChanged(CardInfoPtr activeCard)
|
||||||
|
{
|
||||||
|
emit cardChanged(activeCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(CardInfoPtr activeCard)
|
||||||
|
{
|
||||||
|
emit cardChangedDatabaseDisplay(activeCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onMainboardCardClickedDeckEditor(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit mainboardCardClicked(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabDeckEditorVisualTabWidget::onSideboardCardClickedDeckEditor(QMouseEvent *event,
|
||||||
|
CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit sideboardCardClicked(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,57 @@
|
||||||
|
#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||||
|
#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
|
||||||
|
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
||||||
|
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||||
|
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class TabDeckEditorVisualTabWidget : public QTabWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabDeckEditorVisualTabWidget(QWidget *parent = nullptr,
|
||||||
|
DeckListModel *deckModel = nullptr,
|
||||||
|
CardDatabaseModel *card_database_model = nullptr,
|
||||||
|
CardDatabaseDisplayModel *card_database_display_model = nullptr);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
DeckAnalyticsWidget *deckAnalytics;
|
||||||
|
VisualDatabaseDisplayWidget *visualDatabaseDisplay;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onCardChanged(CardInfoPtr activeCard);
|
||||||
|
void onCardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
||||||
|
void onMainboardCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void onSideboardCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardChanged(CardInfoPtr activeCard);
|
||||||
|
void cardChangedDatabaseDisplay(CardInfoPtr activeCard);
|
||||||
|
void mainboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void sideboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVBoxLayout *layout; // Layout for the tab widget and other controls
|
||||||
|
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
|
||||||
|
|
@ -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,54 @@
|
||||||
|
#include "deck_card_zone_display_widget.h"
|
||||||
|
|
||||||
|
#include "overlapped_card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> cardLists,
|
||||||
|
QString bannerText,
|
||||||
|
int bannerOpacity,
|
||||||
|
int subBannerOpacity)
|
||||||
|
: QWidget(parent), cardLists(cardLists), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity)
|
||||||
|
{
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
banner = new BannerWidget(bannerText, Qt::Orientation::Vertical, bannerOpacity, this);
|
||||||
|
layout->addWidget(banner);
|
||||||
|
|
||||||
|
displayCards();
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
for (QObject *child : layout->children()) {
|
||||||
|
QWidget *widget = qobject_cast<QWidget *>(child);
|
||||||
|
if (widget) {
|
||||||
|
widget->resize(event->size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card);
|
||||||
|
}
|
||||||
|
void DeckCardZoneDisplayWidget::onHover(CardInfoPtr card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckCardZoneDisplayWidget::displayCards()
|
||||||
|
{
|
||||||
|
for (QPair<QString, QList<CardInfoPtr>> &pair : cardLists) {
|
||||||
|
QString criteriaValue = pair.first;
|
||||||
|
QList<CardInfoPtr> cardList = pair.second;
|
||||||
|
|
||||||
|
OverlappedCardGroupDisplayWidget *display_widget =
|
||||||
|
new OverlappedCardGroupDisplayWidget(this, &cardList, criteriaValue, subBannerOpacity);
|
||||||
|
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
layout->addWidget(display_widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||||
|
#define DECK_CARD_ZONE_DISPLAY_WIDGET_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 <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DeckCardZoneDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeckCardZoneDisplayWidget(QWidget *parent,
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> cardLists,
|
||||||
|
QString bannerText,
|
||||||
|
int bannerOpacity,
|
||||||
|
int subBannerOpacity);
|
||||||
|
void addCardsToOverlapWidget();
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void onHover(CardInfoPtr card);
|
||||||
|
void displayCards();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void cardHovered(CardInfoPtr card);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> cardLists;
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
BannerWidget *banner;
|
||||||
|
int bannerOpacity = 20;
|
||||||
|
int subBannerOpacity = 10;
|
||||||
|
OverlapWidget *overlapWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "overlapped_card_group_display_widget.h"
|
||||||
|
|
||||||
|
#include "card_info_picture_with_text_overlay_widget.h"
|
||||||
|
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *parent,
|
||||||
|
QList<CardInfoPtr> *cards,
|
||||||
|
QString bannerText,
|
||||||
|
int bannerOpacity)
|
||||||
|
: QWidget(parent), cardsToDisplay(cards)
|
||||||
|
{
|
||||||
|
layout = new QVBoxLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
setMinimumSize(QSize(0, 0));
|
||||||
|
|
||||||
|
banner = new BannerWidget(bannerText, Qt::Orientation::Vertical, bannerOpacity, this);
|
||||||
|
overlapWidget = new OverlapWidget(this, 80, 1, 1, Qt::Vertical, true);
|
||||||
|
|
||||||
|
layout->addWidget(banner);
|
||||||
|
layout->addWidget(overlapWidget);
|
||||||
|
addCardsToOverlapWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::addCardsToOverlapWidget()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cardsToDisplay->size(); i++) {
|
||||||
|
CardInfoPtr card = cardsToDisplay->at(i);
|
||||||
|
if (card) {
|
||||||
|
CardInfoPictureWithTextOverlayWidget *display =
|
||||||
|
new CardInfoPictureWithTextOverlayWidget(overlapWidget, true);
|
||||||
|
display->setCard(card);
|
||||||
|
|
||||||
|
connect(display, SIGNAL(imageClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(display, SIGNAL(hoveredOnCard(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
overlapWidget->addWidget(display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overlapWidget->adjustMaxColumnsAndRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||||
|
{
|
||||||
|
emit cardClicked(event, card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::onHover(CardInfoPtr card)
|
||||||
|
{
|
||||||
|
emit cardHovered(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlappedCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
|
||||||
|
overlapWidget->resize(event->size());
|
||||||
|
overlapWidget->adjustMaxColumnsAndRows();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Created by ascor on 11/12/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
#define OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_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 <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class OverlappedCardGroupDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OverlappedCardGroupDisplayWidget(QWidget *parent, QList<CardInfoPtr> *cards, QString bannerText, int bannerOpacity);
|
||||||
|
void addCardsToOverlapWidget();
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void onHover(CardInfoPtr card);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||||
|
void cardHovered(CardInfoPtr card);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<CardInfoPtr> *cardsToDisplay;
|
||||||
|
QVBoxLayout *layout;
|
||||||
|
BannerWidget *banner;
|
||||||
|
OverlapWidget *overlapWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "deck_analytics_widget.h"
|
||||||
|
|
||||||
|
DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListModel *deck_list_model)
|
||||||
|
: QWidget(parent), deck_list_model(deck_list_model)
|
||||||
|
{
|
||||||
|
|
||||||
|
this->setMinimumSize(0, 0);
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
this->setStyleSheet("border: 2px solid red;");
|
||||||
|
main_layout = new QHBoxLayout();
|
||||||
|
this->setLayout(main_layout);
|
||||||
|
|
||||||
|
flow_widget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||||
|
this->main_layout->addWidget(flow_widget);
|
||||||
|
|
||||||
|
mana_curve_widget = new ManaCurveWidget(flow_widget);
|
||||||
|
mana_curve_widget->setStyleSheet("border: 2px solid yellow;");
|
||||||
|
|
||||||
|
flow_widget->addWidget(mana_curve_widget);
|
||||||
|
|
||||||
|
mana_devotion_widget = new ManaDevotionWidget(flow_widget, this->deck_list_model);
|
||||||
|
flow_widget->addWidget(mana_devotion_widget);
|
||||||
|
|
||||||
|
mana_base_widget = new ManaBaseWidget(flow_widget, this->deck_list_model);
|
||||||
|
flow_widget->addWidget(mana_base_widget);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef DECK_ANALYTICS_WIDGET_H
|
||||||
|
#define DECK_ANALYTICS_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
|
||||||
|
#include "mana_base_widget.h"
|
||||||
|
#include "mana_curve_widget.h"
|
||||||
|
#include "mana_devotion_widget.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <decklist.h>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
class DeckAnalyticsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckAnalyticsWidget(QWidget *parent = nullptr, DeckListModel *deck_list_model = nullptr);
|
||||||
|
void setDeckList(const DeckList &new_deck_list_model);
|
||||||
|
std::map<int, int> analyzeManaCurve();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deck_list_model;
|
||||||
|
QHBoxLayout *main_layout;
|
||||||
|
FlowWidget *flow_widget;
|
||||||
|
|
||||||
|
ManaCurveWidget *mana_curve_widget;
|
||||||
|
ManaDevotionWidget *mana_devotion_widget;
|
||||||
|
ManaBaseWidget *mana_base_widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DECK_ANALYTICS_WIDGET_H
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
#include "mana_base_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_loader.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../main.h"
|
||||||
|
#include "../general/display/bar_widget.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <decklist.h>
|
||||||
|
#include <regex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
ManaBaseWidget::ManaBaseWidget(QWidget *parent, DeckListModel *deck_list_model)
|
||||||
|
: QWidget(parent), deck_list_model(deck_list_model)
|
||||||
|
{
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
setMinimumSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<char, int> ManaBaseWidget::analyzeManaBase()
|
||||||
|
{
|
||||||
|
manaBaseMap = std::unordered_map<char, int>();
|
||||||
|
InnerDecklistNode *listRoot = deck_list_model->getDeckList()->getRoot();
|
||||||
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
|
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
for (int j = 0; j < currentZone->size(); j++) {
|
||||||
|
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||||
|
if (!currentCard)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||||
|
if (info) {
|
||||||
|
auto devotion = determineManaProduction(info->getText());
|
||||||
|
mergeManaCounts(manaBaseMap, devotion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
// this->setCurve(ManaBaseMap);
|
||||||
|
// mana_curve_widget->updateDisplay();
|
||||||
|
this->updateDisplay();
|
||||||
|
update();
|
||||||
|
return manaBaseMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManaBaseWidget::updateDisplay()
|
||||||
|
{
|
||||||
|
// Clear the layout first
|
||||||
|
if (layout != nullptr) {
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = layout->takeAt(0)) != nullptr) {
|
||||||
|
delete item->widget(); // Delete the widget
|
||||||
|
delete item; // Delete the layout item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If layout is null, create a new layout, otherwise reuse the existing one
|
||||||
|
if (layout == nullptr) {
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalSum = 0;
|
||||||
|
for (auto entry : manaBaseMap) {
|
||||||
|
totalSum += entry.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new widgets to the layout
|
||||||
|
for (auto entry : manaBaseMap) {
|
||||||
|
BarWidget *barWidget = new BarWidget(QString(entry.first), entry.second, totalSum, this);
|
||||||
|
layout->addWidget(barWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(); // Update the widget display
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<char, int> ManaBaseWidget::determineManaProduction(const QString &rulesText)
|
||||||
|
{
|
||||||
|
// Initialize mana counts
|
||||||
|
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}, {'C', 0}};
|
||||||
|
|
||||||
|
// Define regex patterns for different mana production rules
|
||||||
|
QRegularExpression tapAddColorless(R"(\{T\}:\s*Add\s*\{C\}|Add\s*one\s*colorless\s*mana)");
|
||||||
|
QRegularExpression tapAddAnyColor(
|
||||||
|
R"(\{T\}:\s*Add\s*one\s*mana\s*of\s*any\s*color|Add\s*one\s*mana\s*of\s*any\s*color)");
|
||||||
|
QRegularExpression tapAddSpecificColor(
|
||||||
|
R"(\{T\}:\s*Add\s*\{(W|U|B|R|G)\}|Add\s*one\s*(white|blue|black|red|green)\s*mana)");
|
||||||
|
|
||||||
|
// Check for mana production rules in the text
|
||||||
|
if (tapAddColorless.match(rulesText).hasMatch()) {
|
||||||
|
manaCounts['C'] += 1; // Adds colorless mana
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tapAddAnyColor.match(rulesText).hasMatch()) {
|
||||||
|
manaCounts['W'] += 1; // Assumes at least 1 of any color can be produced
|
||||||
|
manaCounts['U'] += 1;
|
||||||
|
manaCounts['B'] += 1;
|
||||||
|
manaCounts['R'] += 1;
|
||||||
|
manaCounts['G'] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for specific color production
|
||||||
|
QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{(W|U|B|R|G)\})");
|
||||||
|
auto match = specificColorRegex.match(rulesText);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString color = match.captured(1);
|
||||||
|
if (color == "W")
|
||||||
|
manaCounts['W'] += 1;
|
||||||
|
else if (color == "U")
|
||||||
|
manaCounts['U'] += 1;
|
||||||
|
else if (color == "B")
|
||||||
|
manaCounts['B'] += 1;
|
||||||
|
else if (color == "R")
|
||||||
|
manaCounts['R'] += 1;
|
||||||
|
else if (color == "G")
|
||||||
|
manaCounts['G'] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return manaCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManaBaseWidget::mergeManaCounts(std::unordered_map<char, int> &manaCounts1,
|
||||||
|
const std::unordered_map<char, int> &manaCounts2)
|
||||||
|
{
|
||||||
|
for (const auto &pair : manaCounts2) {
|
||||||
|
manaCounts1[pair.first] += pair.second; // Add values for matching keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <decklist.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifndef MANA_BASE_WIDGET_H
|
||||||
|
#define MANA_BASE_WIDGET_H
|
||||||
|
|
||||||
|
class ManaBaseWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ManaBaseWidget(QWidget *parent = nullptr, DeckListModel *deck_list_model = nullptr);
|
||||||
|
std::unordered_map<char, int> analyzeManaBase();
|
||||||
|
void updateDisplay();
|
||||||
|
|
||||||
|
std::unordered_map<char, int> determineManaProduction(const QString &manaString);
|
||||||
|
void mergeManaCounts(std::unordered_map<char, int> &manaCounts1, const std::unordered_map<char, int> &manaCounts2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deck_list_model;
|
||||||
|
std::unordered_map<char, int> manaBaseMap;
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MANA_BASE_WIDGET_H
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include "mana_curve_widget.h"
|
||||||
|
|
||||||
|
#include "../general/display/bar_widget.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
ManaCurveWidget::ManaCurveWidget(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
setMinimumSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManaCurveWidget::updateDisplay()
|
||||||
|
{
|
||||||
|
// Clear the layout first
|
||||||
|
if (layout != nullptr) {
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = layout->takeAt(0)) != nullptr) {
|
||||||
|
delete item->widget(); // Delete the widget
|
||||||
|
delete item; // Delete the layout item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If layout is null, create a new layout, otherwise reuse the existing one
|
||||||
|
if (layout == nullptr) {
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalSum = 0;
|
||||||
|
for (auto entry : curve) {
|
||||||
|
totalSum += entry.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a bar for each CMC to the layout
|
||||||
|
for (auto entry : curve) {
|
||||||
|
BarWidget *barWidget = new BarWidget(QString::number(entry.first), entry.second, totalSum, this);
|
||||||
|
layout->addWidget(barWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(); // Update the widget display
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef MANA_CURVE_WIDGET_H
|
||||||
|
#define MANA_CURVE_WIDGET_H
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class ManaCurveWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ManaCurveWidget(QWidget *parent = nullptr);
|
||||||
|
void updateDisplay();
|
||||||
|
|
||||||
|
void setCurve(std::map<int, int> new_curve)
|
||||||
|
{
|
||||||
|
this->curve = std::move(new_curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<int, int> curve;
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MANA_CURVE_WIDGET_H
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include "mana_devotion_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_loader.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../main.h"
|
||||||
|
#include "../general/display/bar_widget.h"
|
||||||
|
|
||||||
|
#include <decklist.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
ManaDevotionWidget::ManaDevotionWidget(QWidget *parent, DeckListModel *deck_list_model)
|
||||||
|
: QWidget(parent), deck_list_model(deck_list_model)
|
||||||
|
{
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
setMinimumSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
||||||
|
{
|
||||||
|
manaDevotionMap = std::unordered_map<char, int>();
|
||||||
|
InnerDecklistNode *listRoot = deck_list_model->getDeckList()->getRoot();
|
||||||
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
|
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
for (int j = 0; j < currentZone->size(); j++) {
|
||||||
|
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||||
|
if (!currentCard)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||||
|
if (info) {
|
||||||
|
auto devotion = countManaSymbols(info->getManaCost());
|
||||||
|
mergeManaCounts(manaDevotionMap, devotion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
// this->setCurve(manaDevotionMap);
|
||||||
|
// mana_curve_widget->updateDisplay();
|
||||||
|
this->updateDisplay();
|
||||||
|
update();
|
||||||
|
return manaDevotionMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManaDevotionWidget::updateDisplay()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Clear the layout first
|
||||||
|
if (layout != nullptr) {
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = layout->takeAt(0)) != nullptr) {
|
||||||
|
delete item->widget(); // Delete the widget
|
||||||
|
delete item; // Delete the layout item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If layout is null, create a new layout, otherwise reuse the existing one
|
||||||
|
if (layout == nullptr) {
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
this->setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalSum = 0;
|
||||||
|
for (auto entry : manaDevotionMap) {
|
||||||
|
totalSum += entry.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new widgets to the layout
|
||||||
|
for (auto entry : manaDevotionMap) {
|
||||||
|
BarWidget *barWidget = new BarWidget(QString(entry.first), entry.second, totalSum, this);
|
||||||
|
layout->addWidget(barWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(); // Update the widget display
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to count mana symbols W, U, B, R, G in the input string
|
||||||
|
std::unordered_map<char, int> ManaDevotionWidget::countManaSymbols(const QString &manaString)
|
||||||
|
{
|
||||||
|
// Only track counts for W, U, B, R, G
|
||||||
|
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}};
|
||||||
|
|
||||||
|
// Convert QString to std::string for regex processing
|
||||||
|
std::string stdManaString = manaString.toStdString();
|
||||||
|
std::regex regexPattern(R"(\{([WUBRG])\/([WUBRG])\})");
|
||||||
|
std::string::const_iterator searchStart(stdManaString.cbegin());
|
||||||
|
std::smatch match;
|
||||||
|
|
||||||
|
// Go through the string and find pairs within {}/ for W, U, B, R, G
|
||||||
|
while (std::regex_search(searchStart, stdManaString.cend(), match, regexPattern)) {
|
||||||
|
char mana1 = match[1].str()[0];
|
||||||
|
char mana2 = match[2].str()[0];
|
||||||
|
|
||||||
|
// Increment the count for both mana symbols
|
||||||
|
manaCounts[mana1]++;
|
||||||
|
manaCounts[mana2]++;
|
||||||
|
|
||||||
|
// Move past the current match
|
||||||
|
searchStart = match.suffix().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now go through the string again but ignore the {}/ parts and non-WUBRG symbols
|
||||||
|
for (int i = 0; i < manaString.size(); ++i) {
|
||||||
|
if (manaString[i] == '{') {
|
||||||
|
// Skip over the {X/Y} pattern
|
||||||
|
while (manaString[i] != '}' && i < manaString.size()) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
} else if (manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||||
|
// If it's one of W, U, B, R, G, count it
|
||||||
|
manaCounts[manaString[i].toLatin1()]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return manaCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManaDevotionWidget::mergeManaCounts(std::unordered_map<char, int> &manaCounts1,
|
||||||
|
const std::unordered_map<char, int> &manaCounts2)
|
||||||
|
{
|
||||||
|
for (const auto &pair : manaCounts2) {
|
||||||
|
manaCounts1[pair.first] += pair.second; // Add values for matching keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef MANA_DEVOTION_WIDGET_H
|
||||||
|
#define MANA_DEVOTION_WIDGET_H
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <decklist.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class ManaDevotionWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ManaDevotionWidget(QWidget *parent = nullptr, DeckListModel *deck_list_model = nullptr);
|
||||||
|
std::unordered_map<char, int> analyzeManaDevotion();
|
||||||
|
void updateDisplay();
|
||||||
|
|
||||||
|
std::unordered_map<char, int> countManaSymbols(const QString &manaString);
|
||||||
|
void mergeManaCounts(std::unordered_map<char, int> &manaCounts1, const std::unordered_map<char, int> &manaCounts2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deck_list_model;
|
||||||
|
std::unordered_map<char, int> manaDevotionMap;
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MANA_DEVOTION_WIDGET_H
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "bar_widget.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
BarWidget::BarWidget(QString label, int value, int total, QWidget *parent)
|
||||||
|
: QWidget(parent), label(std::move(label)), value(value), total(total)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize BarWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
QFontMetrics metrics(font());
|
||||||
|
int labelHeight = metrics.height();
|
||||||
|
int valueHeight = metrics.height();
|
||||||
|
|
||||||
|
// Calculate the height based on total and value
|
||||||
|
int barHeight = total > 0 ? total * 2 : 20; // Adjust factor as necessary for visual size
|
||||||
|
int totalHeight = barHeight + labelHeight + valueHeight + 30; // Extra space for padding
|
||||||
|
return QSize(40, totalHeight); // Width is fixed, height is calculated
|
||||||
|
}
|
||||||
|
|
||||||
|
void BarWidget::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
// Calculate the full bar width and value-specific bar width
|
||||||
|
int fullBarWidth = total; // Full bar (sum of all entries)
|
||||||
|
int valueBarWidth = (total > 0) ? (value * 100 / total) : 0;
|
||||||
|
|
||||||
|
// Draw the full bar background (gray)
|
||||||
|
painter.setBrush(QColor(200, 200, 200)); // Gray background for full bar
|
||||||
|
painter.drawRect(0, 10, 20, fullBarWidth);
|
||||||
|
|
||||||
|
// Draw the value-specific bar (blue)
|
||||||
|
painter.setBrush(QColor(100, 150, 255)); // Blue for the value bar
|
||||||
|
painter.drawRect(0, fullBarWidth + 10, 20, -valueBarWidth);
|
||||||
|
|
||||||
|
// Draw the CMC label
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
QRect textRect(0, fullBarWidth + 10, 20, 30); // Define a rectangle for text
|
||||||
|
painter.drawText(textRect, Qt::AlignCenter, label);
|
||||||
|
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
QRect valueRect(0, 10, 20, fullBarWidth); // Define a rectangle for text
|
||||||
|
painter.drawText(valueRect, Qt::AlignCenter, QString::number(value));
|
||||||
|
|
||||||
|
(void)event; // Suppress unused parameter warning
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef BAR_WIDGET_H
|
||||||
|
#define BAR_WIDGET_H
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class BarWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BarWidget(QString label, int value, int total, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString label; // The CMC value (label for the bar)
|
||||||
|
int value; // The specific value for this CMC (the inner bar length)
|
||||||
|
int total; // Total value for calculating proportional bar length
|
||||||
|
static int totalSum; // The total sum of all entry.second values (shared across instances)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BAR_WIDGET_H
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include "visual_database_display_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../main.h"
|
||||||
|
#include "../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <qpropertyanimation.h>
|
||||||
|
|
||||||
|
VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
||||||
|
CardDatabaseModel *database_model,
|
||||||
|
CardDatabaseDisplayModel *database_display_model)
|
||||||
|
: QWidget(parent), databaseModel(database_model), databaseDisplayModel(database_display_model)
|
||||||
|
{
|
||||||
|
cards = new QList<CardInfoPtr>;
|
||||||
|
connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this,
|
||||||
|
&VisualDatabaseDisplayWidget::modelDirty);
|
||||||
|
|
||||||
|
// Set up main layout and widgets
|
||||||
|
setMinimumSize(0, 0);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
main_layout = new QVBoxLayout();
|
||||||
|
setLayout(main_layout);
|
||||||
|
|
||||||
|
flow_widget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||||
|
main_layout->addWidget(flow_widget);
|
||||||
|
|
||||||
|
overlap_control_widget = new OverlapControlWidget(80, 10, 10, Qt::Vertical, flow_widget);
|
||||||
|
main_layout->addWidget(overlap_control_widget);
|
||||||
|
|
||||||
|
debounce_timer = new QTimer(this);
|
||||||
|
debounce_timer->setSingleShot(true); // Ensure it only fires once after the timeout
|
||||||
|
|
||||||
|
connect(debounce_timer, &QTimer::timeout, this, &VisualDatabaseDisplayWidget::searchModelChanged);
|
||||||
|
setupPaginationControls();
|
||||||
|
loadCurrentPage(); // Load the first page of cards
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
loadCurrentPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit cardClickedDatabaseDisplay(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::onHover(CardInfoPtr hoveredCard)
|
||||||
|
{
|
||||||
|
emit cardHoveredDatabaseDisplay(hoveredCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::populateCards()
|
||||||
|
{
|
||||||
|
this->cards->clear();
|
||||||
|
int rowCount = databaseDisplayModel->rowCount();
|
||||||
|
|
||||||
|
// Calculate the start and end indices for the current page
|
||||||
|
int start = currentPage * cardsPerPage;
|
||||||
|
int end = qMin(start + cardsPerPage, rowCount);
|
||||||
|
|
||||||
|
// Load more cards if we are at the end of the current list and can fetch more
|
||||||
|
if (end >= rowCount && databaseDisplayModel->canFetchMore(QModelIndex())) {
|
||||||
|
databaseDisplayModel->fetchMore(QModelIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = start; row < end; ++row) {
|
||||||
|
QModelIndex index = databaseDisplayModel->index(row, CardDatabaseModel::NameColumn);
|
||||||
|
QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole);
|
||||||
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(name.toString());
|
||||||
|
cards->append(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::searchModelChanged()
|
||||||
|
{
|
||||||
|
currentPage = 0;
|
||||||
|
loadCurrentPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::loadCurrentPage()
|
||||||
|
{
|
||||||
|
// If an animation is already in progress, don't start a new one
|
||||||
|
if (isAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the flag indicating animation is in progress
|
||||||
|
isAnimating = true;
|
||||||
|
|
||||||
|
// Store the original position of the widget
|
||||||
|
QPoint originalPos = flow_widget->pos();
|
||||||
|
|
||||||
|
// Create the first animation to slide the flow_widget
|
||||||
|
QPropertyAnimation *slideOutAnimation = new QPropertyAnimation(flow_widget, "pos");
|
||||||
|
slideOutAnimation->setDuration(300); // Adjust for smoothness
|
||||||
|
slideOutAnimation->setStartValue(originalPos); // Start from the current position
|
||||||
|
|
||||||
|
// Adjust the position (e.g., slide it up or down)
|
||||||
|
QPoint slideOutPos = originalPos;
|
||||||
|
slideOutPos.setY(originalPos.y() - flow_widget->height()); // Slide up (adjust direction as needed)
|
||||||
|
slideOutAnimation->setEndValue(slideOutPos); // End at the new position
|
||||||
|
|
||||||
|
// Create the second animation to bring it back to its original position
|
||||||
|
QPropertyAnimation *slideBackAnimation = new QPropertyAnimation(flow_widget, "pos");
|
||||||
|
slideBackAnimation->setDuration(300); // Duration for smooth transition
|
||||||
|
slideBackAnimation->setStartValue(slideOutPos); // Start from where the first animation ended
|
||||||
|
slideBackAnimation->setEndValue(originalPos); // End at the original position
|
||||||
|
|
||||||
|
// Connect the end of the first animation to the start of the second
|
||||||
|
connect(slideOutAnimation, &QPropertyAnimation::finished, [this, slideBackAnimation]() {
|
||||||
|
// After sliding out, adjust the number of cards, load the new page, and start the slide back animation
|
||||||
|
adjustCardsPerPage(); // Adjust the cards per page before loading
|
||||||
|
populateCards(); // Load the new page of cards
|
||||||
|
updateDisplay(); // Update the visual display
|
||||||
|
|
||||||
|
// Start sliding back to original position
|
||||||
|
slideBackAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Once the second animation finishes, allow new animations to start
|
||||||
|
connect(slideBackAnimation, &QPropertyAnimation::finished, [this]() {
|
||||||
|
isAnimating = false; // Reset the flag after animation finishes
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the slide-out animation
|
||||||
|
slideOutAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::updateDisplay()
|
||||||
|
{
|
||||||
|
// Clear the layout first
|
||||||
|
flow_widget->clearLayout();
|
||||||
|
|
||||||
|
OverlapWidget *printings_group_widget = new OverlapWidget(flow_widget, 0, cardsPerRow, rowsPerColumn, Qt::Vertical);
|
||||||
|
|
||||||
|
// Create card widgets and store their sizes
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> cardDisplays;
|
||||||
|
for (const auto &info : *cards) {
|
||||||
|
if (info) {
|
||||||
|
CardInfoPictureWithTextOverlayWidget *display =
|
||||||
|
new CardInfoPictureWithTextOverlayWidget(printings_group_widget, true);
|
||||||
|
display->setCard(info);
|
||||||
|
cardDisplays.append(display);
|
||||||
|
printings_group_widget->addWidget(display);
|
||||||
|
connect(display, SIGNAL(imageClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
connect(display, SIGNAL(hoveredOnCard(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
} else {
|
||||||
|
qDebug() << "Card not found in database!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the maximum size of the card widgets after they've been added to the layout
|
||||||
|
// adjustCardsPerPage();
|
||||||
|
|
||||||
|
overlap_control_widget->connectOverlapWidget(printings_group_widget);
|
||||||
|
flow_widget->addWidget(printings_group_widget);
|
||||||
|
flow_widget->update();
|
||||||
|
|
||||||
|
update(); // Update the widget display
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::adjustCardsPerPage()
|
||||||
|
{
|
||||||
|
// Calculate available width and height in the OverlapWidget
|
||||||
|
int availableWidth = flow_widget->width();
|
||||||
|
int availableHeight = flow_widget->height();
|
||||||
|
|
||||||
|
QList<CardInfoPictureWithTextOverlayWidget *> cardDisplays;
|
||||||
|
for (OverlapWidget *child : flow_widget->findChildren<OverlapWidget *>()) {
|
||||||
|
for (CardInfoPictureWithTextOverlayWidget *overlapChild :
|
||||||
|
child->findChildren<CardInfoPictureWithTextOverlayWidget *>()) {
|
||||||
|
if (CardInfoPictureWithTextOverlayWidget *cardDisplay =
|
||||||
|
qobject_cast<CardInfoPictureWithTextOverlayWidget *>(overlapChild)) {
|
||||||
|
cardDisplays.append(cardDisplay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the size of the first card display to determine the size of cards
|
||||||
|
if (!cardDisplays.isEmpty()) {
|
||||||
|
int cardWidth = cardDisplays.first()->sizeHint().width();
|
||||||
|
int cardHeight = cardDisplays.first()->sizeHint().height();
|
||||||
|
const int overlapMargin = 10; // Margin between cards
|
||||||
|
|
||||||
|
// Calculate how many cards can fit horizontally and vertically
|
||||||
|
cardsPerRow = availableWidth / (cardWidth + overlapMargin);
|
||||||
|
rowsPerColumn = availableHeight / (cardHeight + overlapMargin);
|
||||||
|
// qDebug() << "available width " << availableWidth << "available height: " << availableHeight;
|
||||||
|
// qDebug() << "width: " << cardWidth << "height: " << cardHeight << "cardsPerRow: " << cardsPerRow <<
|
||||||
|
// "rowsPerColumn: " << rowsPerColumn;
|
||||||
|
|
||||||
|
// Update cardsPerPage based on rows and columns
|
||||||
|
cardsPerPage = cardsPerRow * rowsPerColumn;
|
||||||
|
// qDebug() << "Adjusted cards per page to:" << cardsPerPage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::modelDirty()
|
||||||
|
{
|
||||||
|
debounce_timer->start(debounce_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::sortCardList(const QStringList properties, Qt::SortOrder order = Qt::AscendingOrder)
|
||||||
|
{
|
||||||
|
CardInfoComparator comparator(properties, order);
|
||||||
|
std::sort(cards->begin(), cards->end(), comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::databaseDataChanged(QModelIndex topLeft, QModelIndex bottomRight)
|
||||||
|
{
|
||||||
|
(void)topLeft;
|
||||||
|
(void)bottomRight;
|
||||||
|
updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::wheelEvent(QWheelEvent *event)
|
||||||
|
{
|
||||||
|
if (isAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check scroll direction
|
||||||
|
if (event->angleDelta().y() > 0) {
|
||||||
|
// Scrolling up
|
||||||
|
if (currentPage > 0) {
|
||||||
|
currentPage--;
|
||||||
|
loadCurrentPage(); // Load the previous page
|
||||||
|
}
|
||||||
|
} else if (event->angleDelta().y() < 0) {
|
||||||
|
// Scrolling down
|
||||||
|
if ((currentPage + 1) * cardsPerPage < databaseDisplayModel->rowCount()) {
|
||||||
|
currentPage++;
|
||||||
|
loadCurrentPage(); // Load the next page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent overscrolling by stopping the event if needed
|
||||||
|
if ((currentPage == 0 && event->angleDelta().y() > 0) ||
|
||||||
|
((currentPage + 1) * cardsPerPage >= databaseDisplayModel->rowCount() && event->angleDelta().y() < 0)) {
|
||||||
|
event->ignore(); // Ignore the event to prevent overscrolling
|
||||||
|
} else {
|
||||||
|
event->accept(); // Accept the event if scrolling is valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDatabaseDisplayWidget::setupPaginationControls()
|
||||||
|
{
|
||||||
|
QPushButton *prevButton = new QPushButton("Previous", this);
|
||||||
|
QPushButton *nextButton = new QPushButton("Next", this);
|
||||||
|
|
||||||
|
connect(prevButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
if (currentPage > 0) {
|
||||||
|
currentPage--;
|
||||||
|
loadCurrentPage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(nextButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
if ((currentPage + 1) * cardsPerPage < databaseDisplayModel->rowCount()) {
|
||||||
|
currentPage++;
|
||||||
|
loadCurrentPage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add buttons to layout (for example, at the bottom of the main layout)
|
||||||
|
main_layout->addWidget(prevButton);
|
||||||
|
main_layout->addWidget(nextButton);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||||
|
#define VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_model.h"
|
||||||
|
#include "../../layouts/flow_layout.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_control_widget.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
class VisualDatabaseDisplayWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VisualDatabaseDisplayWidget(QWidget *parent,
|
||||||
|
CardDatabaseModel *database_model,
|
||||||
|
CardDatabaseDisplayModel *database_display_model);
|
||||||
|
void updateDisplay();
|
||||||
|
void adjustCardsPerPage();
|
||||||
|
void populateCards();
|
||||||
|
void searchModelChanged();
|
||||||
|
void loadCurrentPage();
|
||||||
|
void sortCardList(QStringList properties, Qt::SortOrder order);
|
||||||
|
void setDeckList(const DeckList &new_deck_list_model);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void cardHoveredDatabaseDisplay(CardInfoPtr hoveredCard);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void onHover(CardInfoPtr hoveredCard);
|
||||||
|
void databaseDataChanged(QModelIndex topLeft, QModelIndex bottomRight);
|
||||||
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
|
void setupPaginationControls();
|
||||||
|
void modelDirty();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CardDatabaseModel *databaseModel;
|
||||||
|
CardDatabaseDisplayModel *databaseDisplayModel;
|
||||||
|
QList<CardInfoPtr> *cards;
|
||||||
|
QVBoxLayout *main_layout;
|
||||||
|
QScrollArea *scrollArea;
|
||||||
|
FlowWidget *flow_widget;
|
||||||
|
QWidget *overlap_categories;
|
||||||
|
QVBoxLayout *overlap_categories_layout;
|
||||||
|
OverlapControlWidget *overlap_control_widget;
|
||||||
|
QWidget *container;
|
||||||
|
QTimer *debounce_timer;
|
||||||
|
|
||||||
|
bool isAnimating = false;
|
||||||
|
int debounce_time = 300;
|
||||||
|
int currentPage = 0; // Current page index
|
||||||
|
int cardsPerPage = 9; // Number of cards per page
|
||||||
|
int cardsPerRow = 0;
|
||||||
|
int rowsPerColumn = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
#include "visual_deck_editor_widget.h"
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../deck/deck_loader.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../../../game/cards/card_database_manager.h"
|
||||||
|
#include "../../../../main.h"
|
||||||
|
#include "../../../../utility/card_info_comparator.h"
|
||||||
|
#include "../../layouts/flow_layout.h"
|
||||||
|
#include "../../layouts/overlap_layout.h"
|
||||||
|
#include "../../layouts/vertical_flow_layout.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../cards/deck_card_zone_display_widget.h"
|
||||||
|
#include "../cards/overlapped_card_group_display_widget.h"
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_control_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_widget.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *deck_list_model)
|
||||||
|
: QWidget(parent), deck_list_model(deck_list_model)
|
||||||
|
{
|
||||||
|
this->mainDeckCards = new QList<CardInfoPtr>;
|
||||||
|
this->sideboardCards = new QList<CardInfoPtr>;
|
||||||
|
connect(deck_list_model, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged);
|
||||||
|
|
||||||
|
// The Main Widget and Main Layout, which contain a single Widget: The Scroll Area
|
||||||
|
this->setMinimumSize(0, 0);
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
mainLayout = new QVBoxLayout();
|
||||||
|
this->setLayout(mainLayout);
|
||||||
|
|
||||||
|
sortByComboBox = new QComboBox();
|
||||||
|
QStringList sortProperties;
|
||||||
|
sortProperties << "maintype"
|
||||||
|
<< "colors"
|
||||||
|
<< "cmc"
|
||||||
|
<< "name";
|
||||||
|
sortByComboBox->addItems(sortProperties);
|
||||||
|
connect(sortByComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(activeSortCriteriaChanged()));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
flowWidget = new FlowWidget(this, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
|
overlap_control_widget = new OverlapControlWidget(80, 1, 1, Qt::Vertical, this);
|
||||||
|
|
||||||
|
mainLayout->addWidget(sortByComboBox);
|
||||||
|
mainLayout->addWidget(scrollArea);
|
||||||
|
mainLayout->addWidget(overlap_control_widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
zoneContainer->setMaximumWidth(scrollArea->viewport()->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::activeSortCriteriaChanged()
|
||||||
|
{
|
||||||
|
activeSortCriteria = sortByComboBox->currentText();
|
||||||
|
qDebug() << "activeSortCriteria changed: " << activeSortCriteria;
|
||||||
|
updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight)
|
||||||
|
{
|
||||||
|
// Might use these at some point.
|
||||||
|
(void)topLeft;
|
||||||
|
(void)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.
|
||||||
|
QTimer::singleShot(0, this, [this] { updateDisplay(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::updateDisplay()
|
||||||
|
{
|
||||||
|
// Clear the layout first
|
||||||
|
populateCards();
|
||||||
|
zoneContainer = new QWidget(scrollArea);
|
||||||
|
zoneContainerLayout = new QVBoxLayout(zoneContainer);
|
||||||
|
|
||||||
|
DeckCardZoneDisplayWidget *mainBoardWidget =
|
||||||
|
new DeckCardZoneDisplayWidget(zoneContainer, sortCards(mainDeckCards), "Mainboard", 20, 10);
|
||||||
|
connect(mainBoardWidget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
connect(mainBoardWidget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onMainboardClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
|
||||||
|
DeckCardZoneDisplayWidget *sideBoardWidget =
|
||||||
|
new DeckCardZoneDisplayWidget(zoneContainer, sortCards(sideboardCards), "Sideboard", 40, 30);
|
||||||
|
connect(sideBoardWidget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
|
||||||
|
connect(sideBoardWidget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
|
||||||
|
SLOT(onSideboardClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
|
||||||
|
|
||||||
|
zoneContainerLayout->addWidget(mainBoardWidget);
|
||||||
|
zoneContainerLayout->addWidget(sideBoardWidget);
|
||||||
|
|
||||||
|
scrollArea->setWidget(zoneContainer);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> VisualDeckEditorWidget::sortCards(QList<CardInfoPtr> *cardsToSort)
|
||||||
|
{
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> sortedCardGroups;
|
||||||
|
QList<CardInfoPtr> activeList;
|
||||||
|
|
||||||
|
QStringList sortCriteria;
|
||||||
|
sortCriteria.append(activeSortCriteria);
|
||||||
|
sortCardList(sortCriteria, Qt::SortOrder::AscendingOrder);
|
||||||
|
|
||||||
|
QString lastSortCriteriaValue = cardsToSort->isEmpty() ? "" : cardsToSort->at(0)->getProperty(activeSortCriteria);
|
||||||
|
|
||||||
|
for (int i = 0; i < cardsToSort->size(); ++i) {
|
||||||
|
CardInfoPtr info = cardsToSort->at(i);
|
||||||
|
if (info) {
|
||||||
|
QString currentCriteriaValue = info->getProperty(activeSortCriteria);
|
||||||
|
if (currentCriteriaValue != lastSortCriteriaValue) {
|
||||||
|
// Save the current tuple (criteriaValue, list) and start a new list
|
||||||
|
sortedCardGroups.append(qMakePair(lastSortCriteriaValue, activeList));
|
||||||
|
activeList.clear();
|
||||||
|
lastSortCriteriaValue = currentCriteriaValue;
|
||||||
|
}
|
||||||
|
activeList.append(info);
|
||||||
|
} else {
|
||||||
|
qDebug() << "Card not found in database!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last tuple to sortedCardGroups
|
||||||
|
if (!activeList.isEmpty()) {
|
||||||
|
sortedCardGroups.append(qMakePair(lastSortCriteriaValue, activeList));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedCardGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void VisualDeckEditorWidget::sortCards()
|
||||||
|
{
|
||||||
|
QStringList sortCriteria;
|
||||||
|
sortCriteria.append(activeSortCriteria);
|
||||||
|
this->sortCardList(sortCriteria, Qt::SortOrder::AscendingOrder);
|
||||||
|
QString lastSortCriteriaValue = "";
|
||||||
|
overlapCategories = new QWidget(scrollArea);
|
||||||
|
overlapCategoriesLayout = new QVBoxLayout(overlapCategories);
|
||||||
|
OverlapWidget *printings_group_widget = new OverlapWidget(80, 1, 1, Qt::Vertical, overlapCategories);
|
||||||
|
overlap_control_widget->connectOverlapWidget(printings_group_widget);
|
||||||
|
for (int i = 0; i < cards->size(); i++) {
|
||||||
|
CardInfoPtr info = cards->at(i);
|
||||||
|
if (info) {
|
||||||
|
if (info->getProperty(activeSortCriteria) != lastSortCriteriaValue) {
|
||||||
|
printings_group_widget->adjustMaxColumnsAndRows();
|
||||||
|
lastSortCriteriaValue = info->getProperty(activeSortCriteria);
|
||||||
|
printings_group_widget = new OverlapWidget(80, 1, 1, Qt::Vertical, overlapCategories);
|
||||||
|
overlapCategoriesLayout->addWidget(printings_group_widget);
|
||||||
|
overlap_control_widget->connectOverlapWidget(printings_group_widget);
|
||||||
|
}
|
||||||
|
CardInfoPictureWithTextOverlayWidget* display = new
|
||||||
|
CardInfoPictureWithTextOverlayWidget(printings_group_widget, true);
|
||||||
|
|
||||||
|
display->setCard(info);
|
||||||
|
printings_group_widget->addWidget(display);
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Card not found in database!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printings_group_widget->adjustMaxColumnsAndRows();
|
||||||
|
|
||||||
|
scrollArea->setWidget(overlapCategories);
|
||||||
|
update();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::onHover(CardInfoPtr hoveredCard)
|
||||||
|
{
|
||||||
|
emit activeCardChanged(hoveredCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::onMainboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit mainboardCardClicked(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::onSideboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
|
||||||
|
{
|
||||||
|
emit sideboardCardClicked(event, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::populateCards()
|
||||||
|
{
|
||||||
|
mainDeckCards->clear();
|
||||||
|
sideboardCards->clear();
|
||||||
|
|
||||||
|
if (!deck_list_model)
|
||||||
|
return;
|
||||||
|
DeckList *decklist = deck_list_model->getDeckList();
|
||||||
|
if (!decklist)
|
||||||
|
return;
|
||||||
|
InnerDecklistNode *listRoot = decklist->getRoot();
|
||||||
|
if (!listRoot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
|
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
if (!currentZone)
|
||||||
|
continue;
|
||||||
|
for (int j = 0; j < currentZone->size(); j++) {
|
||||||
|
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||||
|
if (!currentCard)
|
||||||
|
continue;
|
||||||
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
|
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
|
||||||
|
currentCard->getName(), currentCard->getCardProviderId());
|
||||||
|
if (info) {
|
||||||
|
if (currentZone->getName() == DECK_ZONE_MAIN) {
|
||||||
|
mainDeckCards->append(info);
|
||||||
|
} else if (currentZone->getName() == DECK_ZONE_SIDE) {
|
||||||
|
sideboardCards->append(info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Card not found in database!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDeckEditorWidget::sortCardList(const QStringList properties, Qt::SortOrder order = Qt::AscendingOrder)
|
||||||
|
{
|
||||||
|
CardInfoComparator comparator(properties, order);
|
||||||
|
std::sort(mainDeckCards->begin(), mainDeckCards->end(), comparator);
|
||||||
|
std::sort(sideboardCards->begin(), sideboardCards->end(), comparator);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef VISUAL_DECK_EDITOR_H
|
||||||
|
#define VISUAL_DECK_EDITOR_H
|
||||||
|
|
||||||
|
#include "../../../../deck/deck_list_model.h"
|
||||||
|
#include "../../../../game/cards/card_database.h"
|
||||||
|
#include "../../layouts/flow_layout.h"
|
||||||
|
#include "../../layouts/vertical_flow_layout.h"
|
||||||
|
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||||
|
#include "../general/layout_containers/flow_widget.h"
|
||||||
|
#include "../general/layout_containers/overlap_control_widget.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <qscrollarea.h>
|
||||||
|
|
||||||
|
class VisualDeckEditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VisualDeckEditorWidget(QWidget *parent = nullptr, DeckListModel *deck_list_model = nullptr);
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
void updateDisplay();
|
||||||
|
QWidget *displayCards(QList<QPair<QString, QList<CardInfoPtr>>> cardLists, int bannerOpacity);
|
||||||
|
QList<QPair<QString, QList<CardInfoPtr>>> sortCards(QList<CardInfoPtr> *cardsToSort);
|
||||||
|
|
||||||
|
OverlapWidget *getSortedCards();
|
||||||
|
void populateCards();
|
||||||
|
void sortCardList(QStringList properties, Qt::SortOrder order);
|
||||||
|
void setDeckList(const DeckList &new_deck_list_model);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void activeCardChanged(CardInfoPtr activeCard);
|
||||||
|
void mainboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void sideboardCardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void onHover(CardInfoPtr hoveredCard);
|
||||||
|
void onMainboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void onSideboardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||||
|
void decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight);
|
||||||
|
void activeSortCriteriaChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deck_list_model;
|
||||||
|
QList<CardInfoPtr> *mainDeckCards;
|
||||||
|
QList<CardInfoPtr> *sideboardCards;
|
||||||
|
QVBoxLayout *mainLayout;
|
||||||
|
QComboBox *sortByComboBox;
|
||||||
|
QString activeSortCriteria = "maintype";
|
||||||
|
FlowWidget *flowWidget;
|
||||||
|
QScrollArea *scrollArea;
|
||||||
|
QWidget *zoneContainer;
|
||||||
|
QVBoxLayout *zoneContainerLayout;
|
||||||
|
OverlapControlWidget *overlap_control_widget;
|
||||||
|
QWidget *container;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VISUAL_DECK_EDITOR_H
|
||||||
|
|
@ -878,6 +878,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||||
&MainWindow::refreshShortcuts);
|
&MainWindow::refreshShortcuts);
|
||||||
refreshShortcuts();
|
refreshShortcuts();
|
||||||
|
connect(CardDatabaseManager::getInstance(), SIGNAL(cardDatabaseLoadingFinished()), tabSupervisor,
|
||||||
|
SLOT(addVisualDeckEditorTab()));
|
||||||
|
|
||||||
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFailed, this,
|
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFailed, this,
|
||||||
&MainWindow::cardDatabaseLoadingFailed);
|
&MainWindow::cardDatabaseLoadingFailed);
|
||||||
|
|
|
||||||
75
cockatrice/src/utility/card_info_comparator.cpp
Normal file
75
cockatrice/src/utility/card_info_comparator.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include "card_info_comparator.h"
|
||||||
|
|
||||||
|
CardInfoComparator::CardInfoComparator(const QStringList &properties, Qt::SortOrder order)
|
||||||
|
: m_properties(properties), m_order(order)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CardInfoComparator::operator()(const CardInfoPtr &a, const CardInfoPtr &b) const
|
||||||
|
{
|
||||||
|
// Iterate over each property in the list
|
||||||
|
for (const QString &property : m_properties) {
|
||||||
|
QVariant valueA = getProperty(a, property);
|
||||||
|
QVariant valueB = getProperty(b, property);
|
||||||
|
|
||||||
|
// Compare the current property
|
||||||
|
if (valueA != valueB) {
|
||||||
|
// If values differ, perform comparison
|
||||||
|
return compareVariants(valueA, valueB) ? (m_order == Qt::AscendingOrder) : (m_order == Qt::DescendingOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all properties are equal, return false (indicating they are considered equal for sorting purposes)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CardInfoComparator::compareVariants(const QVariant &a, const QVariant &b) const
|
||||||
|
{
|
||||||
|
// Determine the type of QVariant based on Qt version
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (a.typeId() != b.typeId()) {
|
||||||
|
#else
|
||||||
|
if (a.type() != b.type()) {
|
||||||
|
#endif
|
||||||
|
// If they are not the same type, compare as strings
|
||||||
|
return a.toString() < b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform type-specific comparison
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
switch (a.typeId()) {
|
||||||
|
#else
|
||||||
|
switch (a.type()) {
|
||||||
|
#endif
|
||||||
|
case QMetaType::Int:
|
||||||
|
return a.toInt() < b.toInt();
|
||||||
|
case QMetaType::Double:
|
||||||
|
return a.toDouble() < b.toDouble();
|
||||||
|
case QMetaType::QString:
|
||||||
|
return a.toString() < b.toString();
|
||||||
|
case QMetaType::Bool:
|
||||||
|
return a.toBool() < b.toBool();
|
||||||
|
default:
|
||||||
|
// Default to comparing as strings
|
||||||
|
return a.toString() < b.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant CardInfoComparator::getProperty(const CardInfoPtr &card, const QString &property) const
|
||||||
|
{
|
||||||
|
// Check if the property exists in the main fields of the class
|
||||||
|
if (property == "name") {
|
||||||
|
return card->getName();
|
||||||
|
} else if (property == "text") {
|
||||||
|
return card->getText();
|
||||||
|
} else if (property == "isToken") {
|
||||||
|
return card->getIsToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, check if it's a custom property in the QVariantHash
|
||||||
|
if (card->hasProperty(property)) {
|
||||||
|
return card->getProperty(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant(); // Return an invalid variant if the property does not exist
|
||||||
|
}
|
||||||
24
cockatrice/src/utility/card_info_comparator.h
Normal file
24
cockatrice/src/utility/card_info_comparator.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef CARD_INFO_COMPARATOR_H
|
||||||
|
#define CARD_INFO_COMPARATOR_H
|
||||||
|
|
||||||
|
#include "../game/cards/card_database.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <Qt>
|
||||||
|
|
||||||
|
class CardInfoComparator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CardInfoComparator(const QStringList &properties, Qt::SortOrder order = Qt::AscendingOrder);
|
||||||
|
bool operator()(const CardInfoPtr &a, const CardInfoPtr &b) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_properties; // List of properties to sort by
|
||||||
|
Qt::SortOrder m_order;
|
||||||
|
|
||||||
|
QVariant getProperty(const CardInfoPtr &card, const QString &property) const;
|
||||||
|
bool compareVariants(const QVariant &a, const QVariant &b) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CARD_INFO_COMPARATOR_H
|
||||||
Loading…
Add table
Add a link
Reference in a new issue