diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc
index 38c40561f..72ca1d83f 100644
--- a/cockatrice/cockatrice.qrc
+++ b/cockatrice/cockatrice.qrc
@@ -379,5 +379,6 @@
resources/tips/tips_of_the_day.xml
resources/help/search.md
+ resources/help/deck_search.md
diff --git a/cockatrice/resources/config/qtlogging.ini b/cockatrice/resources/config/qtlogging.ini
index fcafdd0fd..2cd3d871a 100644
--- a/cockatrice/resources/config/qtlogging.ini
+++ b/cockatrice/resources/config/qtlogging.ini
@@ -62,3 +62,4 @@
# deck_filter_string = false
# filter_string = false
+# syntax_help = false
diff --git a/cockatrice/resources/help/deck_search.md b/cockatrice/resources/help/deck_search.md
new file mode 100644
index 000000000..cb06a40a6
--- /dev/null
+++ b/cockatrice/resources/help/deck_search.md
@@ -0,0 +1,26 @@
+## Deck Search Syntax Help
+-----
+The search bar recognizes a set of special commands.
+In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all
+searches are case insensitive.
+
+- Filename:
+- [red deck wins](#red deck wins) (Any deck filename containing the words red, deck, and wins)
+- ["red deck wins"](#%22red deck wins%22) (Any deck filename containing the exact phrase "red deck wins")
+
+- Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):
+- [[plains]] (Any deck that contains at least one card with "plains" in its name)
+- [[t:legendary]] (Any deck that contains at least one legendary)
+- [[t:legendary]]>5 (Any card that contains at least 5 legendaries)
+- [[]]:100 (Any deck that contains exactly 100 cards)
+
+- Negate:
+- [soldier -aggro](#soldier -aggro) (Any deck filename that contains "soldier", but not "aggro")
+
+- Branching:
+- [t:aggro OR o:control](#t:aggro OR o:control) (Any deck filename that contains either aggro or control)
+
+- Grouping:
+- red -([[]]:100 or aggro) (Any deck that has red in its filename but is not 100 cards or has aggro in its filename)
+
+
diff --git a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
index ecd3d04c6..6e5f39286 100644
--- a/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
+++ b/cockatrice/src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
@@ -1,7 +1,9 @@
#include "visual_deck_storage_search_widget.h"
#include "../../../../game/filters/deck_filter_string.h"
+#include "../../../../game/filters/syntax_help.h"
#include "../../../../settings/cache_settings.h"
+#include "../../pixel_map_generator.h"
/**
* @brief Constructs a PrintingSelectorCardSearchWidget for searching cards by set name or set code.
@@ -18,7 +20,13 @@ VisualDeckStorageSearchWidget::VisualDeckStorageSearchWidget(VisualDeckStorageWi
setLayout(layout);
searchBar = new QLineEdit(this);
- searchBar->setPlaceholderText(tr("Search by filename"));
+ searchBar->setPlaceholderText(tr("Search by filename (or search expression)"));
+ searchBar->setClearButtonEnabled(true);
+ searchBar->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
+
+ auto help = searchBar->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
+ connect(help, &QAction::triggered, this, [this] { createDeckSearchSyntaxHelpWindow(searchBar); });
+
layout->addWidget(searchBar);
// Add a debounce timer for the search bar to limit frequent updates
diff --git a/cockatrice/src/game/filters/syntax_help.cpp b/cockatrice/src/game/filters/syntax_help.cpp
index a4eaf9112..9fb918629 100644
--- a/cockatrice/src/game/filters/syntax_help.cpp
+++ b/cockatrice/src/game/filters/syntax_help.cpp
@@ -9,11 +9,12 @@
*
* @return the QTextBrowser
*/
-static QTextBrowser *createBrowser()
+static QTextBrowser *createBrowser(const QString &helpFile)
{
- QFile file("theme:help/search.md");
+ QFile file(helpFile);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ qCWarning(SyntaxHelpLog) << "Could not open syntax help file: " << helpFile;
return nullptr;
}
@@ -54,9 +55,29 @@ static QTextBrowser *createBrowser()
*/
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit)
{
- auto browser = createBrowser();
+ auto browser = createBrowser("theme:help/search.md");
QObject::connect(browser, &QTextBrowser::anchorClicked,
[lineEdit](const QUrl &link) { lineEdit->setText(link.fragment()); });
QObject::connect(lineEdit, &QObject::destroyed, browser, &QTextBrowser::close);
return browser;
+}
+
+/**
+ * Creates the deck 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 *createDeckSearchSyntaxHelpWindow(QLineEdit *lineEdit)
+{
+ auto browser = createBrowser("theme:help/deck_search.md");
+ QObject::connect(browser, &QTextBrowser::anchorClicked, [lineEdit](const QUrl &link) {
+ if (link.fragment() == "cardSearchSyntaxHelp") {
+ createSearchSyntaxHelpWindow(lineEdit);
+ } else {
+ 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
index 4016e02bb..911c2fdf0 100644
--- a/cockatrice/src/game/filters/syntax_help.h
+++ b/cockatrice/src/game/filters/syntax_help.h
@@ -2,8 +2,13 @@
#define SEARCH_SYNTAX_HELP_H
#include
+#include
#include
+inline Q_LOGGING_CATEGORY(SyntaxHelpLog, "syntax_help");
+
QTextBrowser *createSearchSyntaxHelpWindow(QLineEdit *lineEdit);
+QTextBrowser *createDeckSearchSyntaxHelpWindow(QLineEdit *lineEdit);
+
#endif // SEARCH_SYNTAX_HELP_H