From aa3c8c06258c40462319993f0d28f3a5477d3281 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Fri, 11 Apr 2025 20:00:46 -0700
Subject: [PATCH] Add search filter to card view window (#5791)
* refactor out search syntax help window
* add search bar to ZoneViewWidget
* implement filter logic
---
cockatrice/CMakeLists.txt | 1 +
.../deck_editor_database_display_widget.cpp | 39 +-----------
.../deck_editor_database_display_widget.h | 1 -
cockatrice/src/game/filters/syntax_help.cpp | 62 +++++++++++++++++++
cockatrice/src/game/filters/syntax_help.h | 9 +++
cockatrice/src/game/game_view.cpp | 2 +-
cockatrice/src/game/zones/view_zone.cpp | 17 ++++-
cockatrice/src/game/zones/view_zone.h | 3 +
.../src/game/zones/view_zone_widget.cpp | 19 ++++++
cockatrice/src/game/zones/view_zone_widget.h | 3 +
10 files changed, 116 insertions(+), 40 deletions(-)
create mode 100644 cockatrice/src/game/filters/syntax_help.cpp
create mode 100644 cockatrice/src/game/filters/syntax_help.h
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 84b331f0f..18df9795f 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -157,6 +157,7 @@ set(cockatrice_SOURCES
src/game/filters/filter_string.cpp
src/game/filters/filter_tree.cpp
src/game/filters/filter_tree_model.cpp
+ src/game/filters/syntax_help.cpp
src/game/game_scene.cpp
src/game/game_selector.cpp
src/game/game_view.cpp
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
index 94c6609be..0374503bc 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
@@ -1,6 +1,7 @@
#include "deck_editor_database_display_widget.h"
#include "../../../../game/cards/card_database_manager.h"
+#include "../../../../game/filters/syntax_help.h"
#include "../../../../settings/cache_settings.h"
#include "../../../tabs/abstract_tab_deck_editor.h"
#include "../../../tabs/tab_supervisor.h"
@@ -56,7 +57,7 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(AbstractTabDeck
&DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlEnter, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlC, this, &DeckEditorDatabaseDisplayWidget::copyDatabaseCellContents);
- connect(help, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::showSearchSyntaxHelp);
+ connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); });
databaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), true, this);
databaseModel->setObjectName("databaseModel");
@@ -234,42 +235,6 @@ void DeckEditorDatabaseDisplayWidget::saveDbHeaderState()
SettingsCache::instance().layouts().setDeckEditorDbHeaderState(databaseView->header()->saveState());
}
-void DeckEditorDatabaseDisplayWidget::showSearchSyntaxHelp()
-{
-
- QFile file("theme:help/search.md");
-
- if (!file.open(QFile::ReadOnly | QFile::Text)) {
- return;
- }
-
- QTextStream in(&file);
- QString text = in.readAll();
- file.close();
-
- // Poor Markdown Converter
- auto opts = QRegularExpression::MultilineOption;
- text = text.replace(QRegularExpression("^(###)(.*)", opts), "
\\2
")
- .replace(QRegularExpression("^(##)(.*)", opts), "\\2
")
- .replace(QRegularExpression("^(#)(.*)", opts), "\\2
")
- .replace(QRegularExpression("^------*", opts), "
")
- .replace(QRegularExpression(R"(\[([^[]+)\]\(([^\)]+)\))", opts), R"(\1)");
-
- auto browser = new QTextBrowser;
- browser->setParent(this, Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint |
- Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint);
- browser->setWindowTitle("Search Help");
- browser->setReadOnly(true);
- browser->setMinimumSize({500, 600});
-
- QString sheet = QString("a { text-decoration: underline; color: rgb(71,158,252) };");
- browser->document()->setDefaultStyleSheet(sheet);
-
- browser->setHtml(text);
- connect(browser, &QTextBrowser::anchorClicked, [this](const QUrl &link) { searchEdit->setText(link.fragment()); });
- browser->show();
-}
-
void DeckEditorDatabaseDisplayWidget::setFilterTree(FilterTree *filterTree)
{
databaseDisplayModel->setFilterTree(filterTree);
diff --git a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h
index 9022a2cb7..4010a2954 100644
--- a/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h
+++ b/cockatrice/src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.h
@@ -42,7 +42,6 @@ private:
QWidget *centralWidget;
private slots:
- void showSearchSyntaxHelp();
void retranslateUi();
void updateSearch(const QString &search);
void updateCard(const QModelIndex ¤t, const QModelIndex &);
diff --git a/cockatrice/src/game/filters/syntax_help.cpp b/cockatrice/src/game/filters/syntax_help.cpp
new file mode 100644
index 000000000..a4eaf9112
--- /dev/null
+++ b/cockatrice/src/game/filters/syntax_help.cpp
@@ -0,0 +1,62 @@
+#include "syntax_help.h"
+
+#include
+#include
+#include
+
+/**
+ * Creates the card search syntax help window
+ *
+ * @return the QTextBrowser
+ */
+static QTextBrowser *createBrowser()
+{
+ QFile file("theme:help/search.md");
+
+ if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ return nullptr;
+ }
+
+ QTextStream in(&file);
+ QString text = in.readAll();
+ file.close();
+
+ // Poor Markdown Converter
+ auto opts = QRegularExpression::MultilineOption;
+ text = text.replace(QRegularExpression("^(###)(.*)", opts), "\\2
")
+ .replace(QRegularExpression("^(##)(.*)", opts), "\\2
")
+ .replace(QRegularExpression("^(#)(.*)", opts), "\\2
")
+ .replace(QRegularExpression("^------*", opts), "
")
+ .replace(QRegularExpression(R"(\[([^[]+)\]\(([^\)]+)\))", opts), R"(\1)");
+
+ auto browser = new QTextBrowser();
+ browser->setParent(nullptr, Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
+ Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint |
+ Qt::WindowFullscreenButtonHint);
+ browser->setWindowTitle("Search Help");
+ browser->setReadOnly(true);
+ browser->setMinimumSize({500, 600});
+
+ QString sheet = QString("a { text-decoration: underline; color: rgb(71,158,252) };");
+ browser->document()->setDefaultStyleSheet(sheet);
+ browser->setHtml(text);
+
+ browser->show();
+
+ return browser;
+}
+
+/**
+ * Creates the card search syntax help window and connects its anchorClicked signal to the given QLineEdit.
+ * The window will automatically close when the QLineEdit is destroyed.
+ *
+ * @return the QTextBrowser
+ */
+QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit)
+{
+ auto browser = createBrowser();
+ QObject::connect(browser, &QTextBrowser::anchorClicked,
+ [lineEdit](const QUrl &link) { lineEdit->setText(link.fragment()); });
+ QObject::connect(lineEdit, &QObject::destroyed, browser, &QTextBrowser::close);
+ return browser;
+}
\ No newline at end of file
diff --git a/cockatrice/src/game/filters/syntax_help.h b/cockatrice/src/game/filters/syntax_help.h
new file mode 100644
index 000000000..4016e02bb
--- /dev/null
+++ b/cockatrice/src/game/filters/syntax_help.h
@@ -0,0 +1,9 @@
+#ifndef SEARCH_SYNTAX_HELP_H
+#define SEARCH_SYNTAX_HELP_H
+
+#include
+#include
+
+QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit);
+
+#endif // SEARCH_SYNTAX_HELP_H
diff --git a/cockatrice/src/game/game_view.cpp b/cockatrice/src/game/game_view.cpp
index 7ce9dda3e..969e26e14 100644
--- a/cockatrice/src/game/game_view.cpp
+++ b/cockatrice/src/game/game_view.cpp
@@ -11,7 +11,7 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
{
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
- setFocusPolicy(Qt::NoFocus);
+ setFocusPolicy(Qt::ClickFocus);
setViewportUpdateMode(BoundingRectViewportUpdate);
connect(scene, &GameScene::sceneRectChanged, this, &GameView::updateSceneRect);
diff --git a/cockatrice/src/game/zones/view_zone.cpp b/cockatrice/src/game/zones/view_zone.cpp
index 9e9ba6e81..793f90918 100644
--- a/cockatrice/src/game/zones/view_zone.cpp
+++ b/cockatrice/src/game/zones/view_zone.cpp
@@ -148,7 +148,16 @@ void ZoneViewZone::updateCardIds(CardAction action)
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
void ZoneViewZone::reorganizeCards()
{
- CardList cardsToDisplay(cards);
+ // filter cards
+ CardList cardsToDisplay = CardList(cards.getContentsKnown());
+ for (auto card : cards) {
+ if (filterString.check(card->getInfo())) {
+ card->show();
+ cardsToDisplay.append(card);
+ } else {
+ card->hide();
+ }
+ }
// sort cards
QList sortOptions;
@@ -263,6 +272,12 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
}
}
+void ZoneViewZone::setFilterString(const QString &_filterString)
+{
+ filterString = FilterString(_filterString);
+ reorganizeCards();
+}
+
void ZoneViewZone::setGroupBy(CardList::SortOption _groupBy)
{
groupBy = _groupBy;
diff --git a/cockatrice/src/game/zones/view_zone.h b/cockatrice/src/game/zones/view_zone.h
index 3c69317aa..84fbe5ce6 100644
--- a/cockatrice/src/game/zones/view_zone.h
+++ b/cockatrice/src/game/zones/view_zone.h
@@ -1,6 +1,7 @@
#ifndef ZONEVIEWERZONE_H
#define ZONEVIEWERZONE_H
+#include "../filters/filter_string.h"
#include "select_zone.h"
#include
@@ -35,6 +36,7 @@ private:
int minRows, numberCards;
CardZone *origZone;
bool revealZone, writeableRevealZone;
+ FilterString filterString = FilterString("");
CardList::SortOption groupBy, sortBy;
bool pileView;
bool isReversed;
@@ -96,6 +98,7 @@ public:
}
public slots:
void close();
+ void setFilterString(const QString &_filterString);
void setGroupBy(CardList::SortOption _groupBy);
void setSortBy(CardList::SortOption _sortBy);
void setPileView(int _pileView);
diff --git a/cockatrice/src/game/zones/view_zone_widget.cpp b/cockatrice/src/game/zones/view_zone_widget.cpp
index 7dd21b9d5..85a91afdf 100644
--- a/cockatrice/src/game/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game/zones/view_zone_widget.cpp
@@ -1,7 +1,9 @@
#include "view_zone_widget.h"
+#include "../../client/ui/pixel_map_generator.h"
#include "../../settings/cache_settings.h"
#include "../cards/card_item.h"
+#include "../filters/syntax_help.h"
#include "../game_scene.h"
#include "../player/player.h"
#include "pb/command_shuffle.pb.h"
@@ -41,9 +43,24 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
setFlag(ItemIgnoresTransformations);
QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical);
+ vbox->setSpacing(2);
// If the number is < 0, then it means that we can give the option to make the area sorted
if (numberCards < 0) {
+ // search edit
+ searchEdit.setFocusPolicy(Qt::ClickFocus);
+ searchEdit.setPlaceholderText(tr("Search by card name (or search expressions)"));
+ searchEdit.setClearButtonEnabled(true);
+ searchEdit.addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
+ auto help = searchEdit.addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
+
+ connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(&searchEdit); });
+
+ QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
+ searchEditProxy->setWidget(&searchEdit);
+ searchEditProxy->setZValue(2000000007);
+ vbox->addItem(searchEditProxy);
+
// top row
QGraphicsLinearLayout *hTopRow = new QGraphicsLinearLayout(Qt::Horizontal);
@@ -128,6 +145,8 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
if (CardList::NoSort == static_cast(groupBySelector.currentData().toInt())) {
pileViewCheckBox.setEnabled(false);
}
+
+ connect(&searchEdit, &QLineEdit::textChanged, zone, &ZoneViewZone::setFilterString);
}
setLayout(vbox);
diff --git a/cockatrice/src/game/zones/view_zone_widget.h b/cockatrice/src/game/zones/view_zone_widget.h
index 177bcb92a..04662ebc9 100644
--- a/cockatrice/src/game/zones/view_zone_widget.h
+++ b/cockatrice/src/game/zones/view_zone_widget.h
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
class QLabel;
class QPushButton;
@@ -47,6 +48,8 @@ private:
QPushButton *closeButton;
QScrollBar *scrollBar;
ScrollableGraphicsProxyWidget *scrollBarProxy;
+
+ QLineEdit searchEdit;
QComboBox groupBySelector;
QComboBox sortBySelector;
QCheckBox shuffleCheckBox;