mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
* [Fonts] Restore DeckList Serif default and live-update all role readers * [Fonts] Keep the DeckList fallback on the application font DeckList is read by the deck editor headers, the filter tree and the deck view too, not only by the two surfaces that hardcoded Serif. Resolving the unset role to Serif in appFont() made every user without a fonts.toml see Serif outside the deck list. - appFont(DeckList) falls back to the application font again. - ThemeManager::deckListFont() resolves the role and keeps the Serif fallback for the two historical sites: the deck view zone headers and the printed deck list. - DeckView no longer repaints its viewport on fontsChanged; touching the scene items already schedules the repaint in every attached view. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
193 lines
6.8 KiB
C++
193 lines
6.8 KiB
C++
#include "shortcut_treeview.h"
|
|
|
|
#include "../../interface/theme_manager.h"
|
|
#include "cache_settings.h"
|
|
#include "shortcuts_settings.h"
|
|
|
|
#include <QAbstractItemModel>
|
|
#include <QAbstractItemView>
|
|
#include <QFont>
|
|
#include <QHash>
|
|
#include <QHeaderView>
|
|
#include <QList>
|
|
#include <QModelIndex>
|
|
#include <QRegularExpression>
|
|
#include <QSharedPointer>
|
|
#include <QStandardItem>
|
|
#include <QStandardItemModel>
|
|
#include <QStringList>
|
|
#include <QVariant>
|
|
#include <algorithm>
|
|
#include <qnamespace.h>
|
|
|
|
class QObject;
|
|
class QWidget;
|
|
|
|
ShortcutFilterProxyModel::ShortcutFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Appends the parent and source row together before doing the regex match.
|
|
*/
|
|
bool ShortcutFilterProxyModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
|
|
{
|
|
QModelIndex nameIndex = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
|
|
QModelIndex parentIndex = sourceModel()->index(sourceParent.row(), filterKeyColumn(), sourceParent.parent());
|
|
|
|
QString name = sourceModel()->data(nameIndex).toString();
|
|
QString parentName = sourceModel()->data(parentIndex).toString();
|
|
|
|
QString searchedString = parentName + " " + name;
|
|
|
|
return searchedString.contains(filterRegularExpression());
|
|
}
|
|
|
|
ShortcutTreeView::ShortcutTreeView(QWidget *parent) : QTreeView(parent)
|
|
{
|
|
// model
|
|
shortcutsModel = new QStandardItemModel(this);
|
|
shortcutsModel->setColumnCount(3);
|
|
populateShortcutsModel();
|
|
|
|
// filter proxy
|
|
proxyModel = new ShortcutFilterProxyModel(this);
|
|
proxyModel->setRecursiveFilteringEnabled(true);
|
|
proxyModel->setSourceModel(shortcutsModel);
|
|
proxyModel->setDynamicSortFilter(true);
|
|
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
proxyModel->setFilterKeyColumn(0);
|
|
|
|
QTreeView::setModel(proxyModel);
|
|
|
|
// treeview
|
|
hideColumn(2);
|
|
|
|
setUniformRowHeights(true);
|
|
setAlternatingRowColors(true);
|
|
|
|
setSortingEnabled(true);
|
|
proxyModel->sort(0, Qt::AscendingOrder);
|
|
|
|
header()->setSectionResizeMode(QHeaderView::Interactive);
|
|
header()->setSortIndicator(0, Qt::AscendingOrder);
|
|
setSelectionMode(SingleSelection);
|
|
setSelectionBehavior(SelectRows);
|
|
|
|
expandAll();
|
|
|
|
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
|
&ShortcutTreeView::refreshShortcuts);
|
|
|
|
// Group headers store their font on the item; re-apply the role family on
|
|
// font changes (setFont emits itemChanged, which repaints the rows).
|
|
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
|
QFont groupFont = themeManager->appFont(AppFont::InterfaceDefault);
|
|
groupFont.setBold(true);
|
|
for (int row = 0; row < shortcutsModel->rowCount(); ++row) {
|
|
if (auto *groupItem = shortcutsModel->item(row)) {
|
|
groupItem->setFont(groupFont);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void ShortcutTreeView::populateShortcutsModel()
|
|
{
|
|
QHash<QString, QStandardItem *> parentItems;
|
|
QStandardItem *curParent = nullptr;
|
|
for (const auto &key : SettingsCache::instance().shortcuts().getAllShortcutKeys()) {
|
|
QString name = SettingsCache::instance().shortcuts().getShortcut(key).getName();
|
|
QString group = SettingsCache::instance().shortcuts().getShortcut(key).getGroupName();
|
|
QString shortcut = SettingsCache::instance().shortcuts().getShortcutString(key);
|
|
|
|
if (parentItems.contains(group)) {
|
|
curParent = parentItems.value(group);
|
|
} else {
|
|
curParent = new QStandardItem(group);
|
|
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
|
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
|
font.setBold(true);
|
|
curParent->setFont(font);
|
|
parentItems.insert(group, curParent);
|
|
}
|
|
|
|
QList<QStandardItem *> list = {};
|
|
list << new QStandardItem(name) << new QStandardItem(shortcut) << new QStandardItem(key);
|
|
curParent->appendRow(list);
|
|
}
|
|
|
|
for (const auto &parent : parentItems) {
|
|
shortcutsModel->appendRow(parent);
|
|
}
|
|
}
|
|
|
|
void ShortcutTreeView::retranslateUi()
|
|
{
|
|
shortcutsModel->setHeaderData(0, Qt::Horizontal, tr("Action"));
|
|
shortcutsModel->setHeaderData(1, Qt::Horizontal, tr("Shortcut"));
|
|
refreshShortcuts();
|
|
}
|
|
|
|
/**
|
|
* Loops over the model and reloads all rows
|
|
*/
|
|
static void loopOverModel(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex())
|
|
{
|
|
for (int r = 0; r < model->rowCount(parent); ++r) {
|
|
const auto friendlyNameIndex = model->index(r, 0, parent);
|
|
|
|
if (model->hasChildren(friendlyNameIndex)) {
|
|
const auto childIndex = model->index(0, 2, friendlyNameIndex);
|
|
const auto key = model->data(childIndex).toString();
|
|
const auto shortcutGroupName = SettingsCache::instance().shortcuts().getShortcut(key).getGroupName();
|
|
model->setData(friendlyNameIndex, shortcutGroupName);
|
|
|
|
loopOverModel(model, friendlyNameIndex);
|
|
} else {
|
|
const auto shortcutSequenceIndex = model->index(r, 1, parent);
|
|
const auto keyIndex = model->index(r, 2, parent);
|
|
const auto key = model->data(keyIndex).toString();
|
|
|
|
const auto shortcutKey = SettingsCache::instance().shortcuts().getShortcut(key).getName();
|
|
const auto shortcutSequence = SettingsCache::instance().shortcuts().getShortcutString(key);
|
|
model->setData(friendlyNameIndex, shortcutKey);
|
|
model->setData(shortcutSequenceIndex, shortcutSequence);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ShortcutTreeView::refreshShortcuts()
|
|
{
|
|
loopOverModel(shortcutsModel);
|
|
}
|
|
|
|
void ShortcutTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex & /* previous */)
|
|
{
|
|
QTreeView::scrollTo(current, QAbstractItemView::EnsureVisible);
|
|
if (current.parent().isValid()) {
|
|
auto shortcutName = model()->data(model()->index(current.row(), 2, current.parent())).toString();
|
|
emit currentItemChanged(shortcutName);
|
|
} else {
|
|
// emit empty string if the selection is a category header
|
|
emit currentItemChanged("");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The search string is split by word.
|
|
* A String is a match as long as it contains all the words in the search string in order
|
|
*/
|
|
void ShortcutTreeView::updateSearchString(const QString &searchString)
|
|
{
|
|
QStringList searchWords = searchString.split(" ", Qt::SkipEmptyParts);
|
|
|
|
auto escapeRegex = [](const QString &s) { return QRegularExpression::escape(s); };
|
|
std::transform(searchWords.begin(), searchWords.end(), searchWords.begin(), escapeRegex);
|
|
|
|
auto regex = QRegularExpression(searchWords.join(".*"), QRegularExpression::CaseInsensitiveOption);
|
|
|
|
proxyModel->setFilterRegularExpression(regex);
|
|
expandAll();
|
|
}
|